Merge "Revert "Add CTS test cases for new exposing APIs(1/2)"" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 2047168..eed248b 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -310,6 +310,8 @@
 aconfig_declarations {
     name: "android.os.flags-aconfig",
     package: "android.os",
+    exportable: true,
+    container: "system",
     srcs: ["core/java/android/os/*.aconfig"],
 }
 
@@ -326,6 +328,13 @@
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
+java_aconfig_library {
+    name: "android.os.flags-aconfig-java-export",
+    aconfig_declarations: "android.os.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+    mode: "exported",
+}
+
 // VirtualDeviceManager
 cc_aconfig_library {
     name: "android.companion.virtualdevice.flags-aconfig-cc",
diff --git a/Android.bp b/Android.bp
index 019bf6508..8d7ab98 100644
--- a/Android.bp
+++ b/Android.bp
@@ -387,6 +387,7 @@
         // system propagates "required" properly.
         "gps_debug.conf",
         "protolog.conf.json.gz",
+        "core.protolog.pb",
         "framework-res",
         // any install dependencies should go into framework-minus-apex-install-dependencies
         // rather than here to avoid bloating incremental build time
diff --git a/INPUT_OWNERS b/INPUT_OWNERS
index 44b2f38..06ead06 100644
--- a/INPUT_OWNERS
+++ b/INPUT_OWNERS
@@ -1,4 +1,6 @@
 # Bug component: 136048
+arpitks@google.com
+asmitapoddar@google.com
 hcutts@google.com
 joseprio@google.com
 michaelwr@google.com
diff --git a/OWNERS b/OWNERS
index 6bab92b..7ceca32 100644
--- a/OWNERS
+++ b/OWNERS
@@ -32,6 +32,7 @@
 per-file TestProtoLibraries.bp = file:platform/platform_testing:/libraries/health/OWNERS
 per-file TestProtoLibraries.bp = file:platform/tools/tradefederation:/OWNERS
 
+per-file INPUT_OWNERS = file:/INPUT_OWNERS
 per-file ZYGOTE_OWNERS = file:/ZYGOTE_OWNERS
 per-file SQLITE_OWNERS = file:/SQLITE_OWNERS
 
diff --git a/Ravenwood.bp b/Ravenwood.bp
index 2df6d58..f43c37b 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -145,6 +145,17 @@
 }
 
 java_library {
+    name: "services.fakes.ravenwood-jarjar",
+    installable: false,
+    srcs: [":services.fakes-sources"],
+    libs: [
+        "ravenwood-framework",
+        "services.core.ravenwood",
+    ],
+    jarjar_rules: ":ravenwood-services-jarjar-rules",
+}
+
+java_library {
     name: "mockito-ravenwood-prebuilt",
     installable: false,
     static_libs: [
@@ -189,14 +200,21 @@
         "ravenwood-helper-runtime",
         "hoststubgen-helper-runtime.ravenwood",
         "services.core.ravenwood-jarjar",
+        "services.fakes.ravenwood-jarjar",
 
         // Provide runtime versions of utils linked in below
         "junit",
         "truth",
+        "flag-junit",
+        "ravenwood-framework",
         "ravenwood-junit-impl",
+        "ravenwood-junit-impl-flag",
         "mockito-ravenwood-prebuilt",
         "inline-mockito-ravenwood-prebuilt",
     ],
+    jni_libs: [
+        "libandroid_runtime",
+    ],
 }
 
 android_ravenwood_libgroup {
@@ -204,6 +222,8 @@
     libs: [
         "junit",
         "truth",
+        "flag-junit",
+        "ravenwood-framework",
         "ravenwood-junit",
         "mockito-ravenwood-prebuilt",
         "inline-mockito-ravenwood-prebuilt",
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java
index d14e93e..80a9c06 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java
@@ -27,8 +27,8 @@
 import android.perftests.utils.BitmapUtils;
 import android.perftests.utils.PerfStatusReporter;
 import android.perftests.utils.PerfTestActivity;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.AndroidJUnit4;
 
diff --git a/apct-tests/perftests/core/src/android/libcore/AdditionPerfTest.java b/apct-tests/perftests/core/src/android/libcore/AdditionPerfTest.java
index aa47e0a..80cd86c 100644
--- a/apct-tests/perftests/core/src/android/libcore/AdditionPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/AdditionPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/ArrayCopyPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ArrayCopyPerfTest.java
index 97ab6c7..2f6c378 100644
--- a/apct-tests/perftests/core/src/android/libcore/ArrayCopyPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ArrayCopyPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/ArrayIterationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ArrayIterationPerfTest.java
index bb452d3..d17add7 100644
--- a/apct-tests/perftests/core/src/android/libcore/ArrayIterationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ArrayIterationPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/ArrayListIterationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ArrayListIterationPerfTest.java
index ff6d46f..3a57db8 100644
--- a/apct-tests/perftests/core/src/android/libcore/ArrayListIterationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ArrayListIterationPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/BigIntegerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/BigIntegerPerfTest.java
index e0c12dd..3fb3bc8 100644
--- a/apct-tests/perftests/core/src/android/libcore/BigIntegerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/BigIntegerPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/BufferedZipFilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/BufferedZipFilePerfTest.java
index 04ef09e4..2a1b5d1 100644
--- a/apct-tests/perftests/core/src/android/libcore/BufferedZipFilePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/BufferedZipFilePerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/ClassLoaderResourcePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ClassLoaderResourcePerfTest.java
index 4ae88b8..5f599ea 100644
--- a/apct-tests/perftests/core/src/android/libcore/ClassLoaderResourcePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ClassLoaderResourcePerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Assert;
diff --git a/apct-tests/perftests/core/src/android/libcore/ClonePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ClonePerfTest.java
index 5e73916..ea24984 100644
--- a/apct-tests/perftests/core/src/android/libcore/ClonePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ClonePerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java
index 3ebaa4c..82247dc 100644
--- a/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/FieldAccessPerfTest.java b/apct-tests/perftests/core/src/android/libcore/FieldAccessPerfTest.java
index da94ae1..0bebf04 100644
--- a/apct-tests/perftests/core/src/android/libcore/FieldAccessPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/FieldAccessPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/HashedCollectionsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/HashedCollectionsPerfTest.java
index 9446d99c..55c1027 100644
--- a/apct-tests/perftests/core/src/android/libcore/HashedCollectionsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/HashedCollectionsPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTest.java
index be2a7e9..da60a77 100644
--- a/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/MethodInvocationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/MethodInvocationPerfTest.java
index ca99779..6d9d0c9 100644
--- a/apct-tests/perftests/core/src/android/libcore/MethodInvocationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/MethodInvocationPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/MultiplicationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/MultiplicationPerfTest.java
index 8496fbe..09b0977 100644
--- a/apct-tests/perftests/core/src/android/libcore/MultiplicationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/MultiplicationPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/ReferenceGetPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ReferenceGetPerfTest.java
index bb79424..ba21ed3 100644
--- a/apct-tests/perftests/core/src/android/libcore/ReferenceGetPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ReferenceGetPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java
index 05a3e12..293752e 100644
--- a/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/SmallBigIntegerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/SmallBigIntegerPerfTest.java
index 65a2fdb..528b751 100644
--- a/apct-tests/perftests/core/src/android/libcore/SmallBigIntegerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/SmallBigIntegerPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/StringDexCachePerfTest.java b/apct-tests/perftests/core/src/android/libcore/StringDexCachePerfTest.java
index 4f5c54d..1f301ac 100644
--- a/apct-tests/perftests/core/src/android/libcore/StringDexCachePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/StringDexCachePerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/StringIterationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/StringIterationPerfTest.java
index 08ad926..4268325 100644
--- a/apct-tests/perftests/core/src/android/libcore/StringIterationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/StringIterationPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/SystemArrayCopyPerfTest.java b/apct-tests/perftests/core/src/android/libcore/SystemArrayCopyPerfTest.java
index 20f1309..6363e9c 100644
--- a/apct-tests/perftests/core/src/android/libcore/SystemArrayCopyPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/SystemArrayCopyPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/VirtualVersusInterfacePerfTest.java b/apct-tests/perftests/core/src/android/libcore/VirtualVersusInterfacePerfTest.java
index 7e71976..cb3d3ac 100644
--- a/apct-tests/perftests/core/src/android/libcore/VirtualVersusInterfacePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/VirtualVersusInterfacePerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java b/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java
index b1b594d..5be8ee6 100644
--- a/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/XmlSerializerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/XmlSerializerPerfTest.java
index 412cb5a..a37b89d 100644
--- a/apct-tests/perftests/core/src/android/libcore/XmlSerializerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/XmlSerializerPerfTest.java
@@ -18,9 +18,9 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Xml;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import libcore.util.XmlObjectFactory;
diff --git a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
index 3a45d40..ed669be 100644
--- a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java
index 2e89518..d239a05 100644
--- a/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java
index d38d519..487295c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java
index cc56868..adc5d8c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java
index 662694b..286d703 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java
index 2c0473e..d646202 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java
index 6a2ce58..b887f40 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/BulkPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/BulkPerfTest.java
index b7b7e83..e4eaf12 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/BulkPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BulkPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java
index 9ac36d0..cb2438e 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java
index 5dd9d6e..9ee927c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java
index 0a59899..e4a4db7 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java
index 8da13a9..858c101 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java
index 048c50f..a2fb7d7 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java
index b753006..2047444 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java
@@ -18,8 +18,8 @@
 import android.icu.lang.UCharacter;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java
index 1d33fcb..4ce8b41 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java
index 35730ec..6a7ec1a 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java
index 42b0588..238c028 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java
index 6728e73..7e55660 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java
index 69197c3..100798a 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DateFormatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DateFormatPerfTest.java
index 4dba139..b6784a8 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DateFormatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DateFormatPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatPerfTest.java
index f3eddab..52f9873 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatSymbolsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatSymbolsPerfTest.java
index 2bf0418..6105420 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatSymbolsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatSymbolsPerfTest.java
@@ -17,8 +17,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DefaultCharsetPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DefaultCharsetPerfTest.java
index c3320a4..fae74a5 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DefaultCharsetPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DefaultCharsetPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DnsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DnsPerfTest.java
index 7c52ac4..2915363 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DnsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DnsPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DoPrivilegedPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DoPrivilegedPerfTest.java
index d133359..dd7e5cc 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DoPrivilegedPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DoPrivilegedPerfTest.java
@@ -18,15 +18,14 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/DoublePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/DoublePerfTest.java
index 38904af..e034a47 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DoublePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DoublePerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/EqualsHashCodePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/EqualsHashCodePerfTest.java
index 8391203..fe1b599 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/EqualsHashCodePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/EqualsHashCodePerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
index 7712aee..ecbfc71 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/FilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/FilePerfTest.java
index 783136a..0c14d64 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/FilePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/FilePerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/FloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/FloatPerfTest.java
index a995f5c..7d7d83b 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/FloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/FloatPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/FormatterPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/FormatterPerfTest.java
index 94c4f08..08dda53 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/FormatterPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/FormatterPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/IdnPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/IdnPerfTest.java
index c60930f..a09ad80 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/IdnPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/IdnPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/IntConstantDivisionPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/IntConstantDivisionPerfTest.java
index abcc972..be22814 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/IntConstantDivisionPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/IntConstantDivisionPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/IntConstantMultiplicationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/IntConstantMultiplicationPerfTest.java
index c9f0616..4337c90 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/IntConstantMultiplicationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/IntConstantMultiplicationPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/IntConstantRemainderPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/IntConstantRemainderPerfTest.java
index 78f744c..1b6c502 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/IntConstantRemainderPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/IntConstantRemainderPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/IntegralToStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/IntegralToStringPerfTest.java
index 5129fcb..0aa854e 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/IntegralToStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/IntegralToStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/KeyPairGeneratorPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/KeyPairGeneratorPerfTest.java
index 80c4487..9b3d7a0 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/KeyPairGeneratorPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/KeyPairGeneratorPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/LoopingBackwardsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/LoopingBackwardsPerfTest.java
index c9b0cbe..1a9e19a 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/LoopingBackwardsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/LoopingBackwardsPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/MathPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/MathPerfTest.java
index 4c2d7fb..a8a704c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/MathPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/MathPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/MessageDigestPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/MessageDigestPerfTest.java
index 2dc947a..6da9666 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/MessageDigestPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/MessageDigestPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/MutableIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/MutableIntPerfTest.java
index d9d4bb5..060d18f 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/MutableIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/MutableIntPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatPerfTest.java
index dae185e..7cb3b22 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java
index 5ff2b22..272b45a 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/PriorityQueuePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/PriorityQueuePerfTest.java
index 48450b4..c3a0966 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/PriorityQueuePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/PriorityQueuePerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/PropertyAccessPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/PropertyAccessPerfTest.java
index 21ccba5..2ac56be 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/PropertyAccessPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/PropertyAccessPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ProviderPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ProviderPerfTest.java
index f7bcf12..7ad0141 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ProviderPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ProviderPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/RandomPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/RandomPerfTest.java
index d8bff4c..c7b6cb5 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/RandomPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/RandomPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/RealToStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/RealToStringPerfTest.java
index 2542df9..44e5f22 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/RealToStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/RealToStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ReflectionPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ReflectionPerfTest.java
index b06662c..6e00b1083 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ReflectionPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ReflectionPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SSLLoopbackPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SSLLoopbackPerfTest.java
index 694d609..5a9b5c3 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SSLLoopbackPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SSLLoopbackPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import libcore.java.security.TestKeyStore;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SSLSocketFactoryPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SSLSocketFactoryPerfTest.java
index bdbbcb0..6d48cf2 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SSLSocketFactoryPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SSLSocketFactoryPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SchemePrefixPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SchemePrefixPerfTest.java
index 5ad62de..8641629 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SchemePrefixPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SchemePrefixPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SerializationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SerializationPerfTest.java
index 1ec22d2..afd1191 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SerializationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SerializationPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SignaturePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SignaturePerfTest.java
index a9a0788..6c26133 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SignaturePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SignaturePerfTest.java
@@ -17,7 +17,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/SimpleDateFormatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/SimpleDateFormatPerfTest.java
index c25b0ce..274b51f 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SimpleDateFormatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SimpleDateFormatPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StrictMathPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StrictMathPerfTest.java
index eeccb5b..b4c427b 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StrictMathPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StrictMathPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringBuilderPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringBuilderPerfTest.java
index 10fa8b9..2235cc5 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringBuilderPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringBuilderPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringEqualsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringEqualsPerfTest.java
index 6854c0d..9ab5000 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringEqualsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringEqualsPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import junit.framework.Assert;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringIsEmptyPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringIsEmptyPerfTest.java
index 79ff646..b1e749c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringIsEmptyPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringIsEmptyPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringLengthPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringLengthPerfTest.java
index 8dbf9f5..9e57591 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringLengthPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringLengthPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringPerfTest.java
index 36db014..a80514c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringReplaceAllPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringReplaceAllPerfTest.java
index 5b4423a..78ae395 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringReplaceAllPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringReplaceAllPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringReplacePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringReplacePerfTest.java
index 4d5c792..73911c7 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringReplacePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringReplacePerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringSplitPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringSplitPerfTest.java
index 2bb25ac..1539271 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringSplitPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringSplitPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringToBytesPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringToBytesPerfTest.java
index c004d95..0d5e62b 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringToBytesPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringToBytesPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringToRealPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringToRealPerfTest.java
index 15516fc..ecdf809 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringToRealPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringToRealPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ThreadLocalPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ThreadLocalPerfTest.java
index f256555..2b2a6b5 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ThreadLocalPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ThreadLocalPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/TimeZonePerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/TimeZonePerfTest.java
index 8274512..6eb8fcc 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/TimeZonePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/TimeZonePerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/XMLEntitiesPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/XMLEntitiesPerfTest.java
index ae1e8bc..288c646 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/XMLEntitiesPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/XMLEntitiesPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianIntPerfTest.java
index e7bb8f8..003c957 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianStringPerfTest.java
index 5bac46a..4f21618 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianIntPerfTest.java
index 1005a70..210014a 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianStringPerfTest.java
index 5224ad3..22c6827 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianIntPerfTest.java
index 06696ef..5b39109 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianStringPerfTest.java
index a784c52..883e8a7 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianIntPerfTest.java
index 4ce0078..50bc85c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianStringPerfTest.java
index 587e201..13fa2bf 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest.java
index e06b534..85c9bae9 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest.java
index 0fd16a0..2b8f430 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest.java
index 7ad42d0..246fa43 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest.java
index 76e1f47..d12ffae 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianIntPerfTest.java
index b4b7840..5ced115 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianStringPerfTest.java
index 09ed167..b955d50 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest.java
index 920d2e4..601ff34 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest.java
index 55ed789..0e567f9 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest.java
index ea3057b..6be2870 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest.java
index 20558aa9..84c186b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest.java
index d7b1d29..b093234 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest.java
index d138dc9..0d2037b4 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianIntPerfTest.java
index 36153f2..ee31973 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianStringPerfTest.java
index bf4fbc4..0571fef 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest.java
index d3c1b36..f619dab 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest.java
index 90e69a1..fc443fa 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianIntPerfTest.java
index 96bc104..bf3d58b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianStringPerfTest.java
index 2679494..1f4bc31 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest.java
index 170dce7..2085552 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest.java
index 11d12db..d9c7d7b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianIntPerfTest.java
index bd2a600..acd2533 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianStringPerfTest.java
index 99a09cd..de9944a 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewBigEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewBigEndianIntPerfTest.java
index db83606..a863929 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewBigEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewBigEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewLittleEndianIntPerfTest.java
index 4a8f924..4999b9b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianIntPerfTest.java
index 4e4a9ee..ee80a6f 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianStringPerfTest.java
index 3e7de1d..ec29f7a 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianIntPerfTest.java
index 67d53b3..ee6a669 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianStringPerfTest.java
index 470a1ce..1702b84 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest.java
index 8a982c2..514ddb9 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest.java
index 2c17a69..fbcee69 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianIntPerfTest.java
index 099b1f4..2c56588 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianStringPerfTest.java
index 7f6b4b8..8fce69e 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianIntPerfTest.java
index 8592d30..ef530607 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianStringPerfTest.java
index 539bd2a..64c0898 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest.java
index a36a7b6..939100c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest.java
index 90d2a70..728b199 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest.java
index 4e5fcf3..bf5ef99 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest.java
index fd0abf8..d15705e 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest.java
index 9272b11..222a60d 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest.java
index a896d0a..7436476 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianFloatPerfTest.java
index 671b0a3..cca97f4 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianFloatPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianIntPerfTest.java
index 1eb3f92..170ee73 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest.java
index f23d5e2..184f796 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest.java
index 1613798..7e75c44 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest.java
index 14f1c00..39c386b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest.java
index 8327caf..04ab531 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest.java
index 6c211fb..b71351f 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianIntPerfTest.java
index d02cd73..e3955c0 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest.java
index 0777586..adf05a6 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest.java
index 24a949f..4d657d9 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest.java
index 4b94bbe..dc64174 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest.java
index 1784c05..25d5631 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest.java
index f85d3ee..de2d548 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest.java
index 81f6779..36544c6 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest.java
index 9436fad..fb36d0c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest.java
index 9ebc458..4194b12 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest.java
index ea159a1..355c6e8 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest.java
index a42ec7e..401079d 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest.java
index 6f1007e5..322dcbf 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest.java
index 6a73818..c982814 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest.java
index e9a365b..0b1cb32 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest.java
index fc9191c..4737072 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest.java
index 5919a1d..204cd70 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest.java
index 313e580..b3ffed7 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest.java
index 9c8b3ae..d0ab8de 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest.java
index ea618cc..b378b68 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest.java
index df6f470..c7c66fe 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest.java
index 63fd740..98d6bd7 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest.java
index a96031e..206358f 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest.java
index 3bc25fb..0532e73 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianIntPerfTest.java
index 7ffdf11..f192d71 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianStringPerfTest.java
index cc7f3be..0a8909c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest.java
index 8d54c00..bfcb0f4 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest.java
index 22e92dd..c6b0509 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest.java
index 08ddc8b..45a01ed 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest.java
index 429e090..3047281 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianIntPerfTest.java
index d5b31f6..6f1f1a0 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianStringPerfTest.java
index 8667aaa..c4d279f 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianIntPerfTest.java
index aa20246..c4f6005 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianStringPerfTest.java
index 9e0210f..a6858c2 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewBigEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewBigEndianIntPerfTest.java
index d489168..a994cbe 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewBigEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewBigEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewLittleEndianIntPerfTest.java
index b06d7ef..65412ec 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianIntPerfTest.java
index 8446937..573b0ff 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianStringPerfTest.java
index 34540a3..fe3c0fc 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianIntPerfTest.java
index c79b513..f398899 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianStringPerfTest.java
index 028130d..7493120 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest.java
index 06a5a8c..5e73269 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest.java
index 78eefc8..9a217d1 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianIntPerfTest.java
index cd1bd48..1ce2270 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianStringPerfTest.java
index 6c0740c..ed84528 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest.java
index b95f24b..aeb9640 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest.java
index b03cf82..8959a0c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianIntPerfTest.java
index c98c092..4007722 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianStringPerfTest.java
index 625cfc7..7323158 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianIntPerfTest.java
index 58319b3..f4119c2 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianStringPerfTest.java
index f741542..9b9c261 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest.java
index 87f6a78..f125384 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest.java
index 610345f..2ad605d 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest.java
index 519d4fd..5ef3bf0 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest.java
index 322cf63..0c4ed66 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest.java
index f8ccbad..db6bd24 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest.java
index 16f1059..d2b0bf7 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest.java
index c7084fe..3cd5ae6 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest.java
index 9d526b8..6ddfc25 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest.java
index 8372f6c..375f0bc 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest.java
index 87e47e7..7e2492a 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest.java
index aa2e104..190118c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest.java
index ebaa080..484ba1b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest.java
index d90356a..80e4e15 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest.java
index 6db995a..fa26c59 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest.java
index ecea19e..16bf2a20 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest.java
index ab86284..e1716de 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest.java
index 23a33f5..dc6f2ad 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest.java b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest.java
index 270b5ad..d1096c6 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/rubidium/src/android/rubidium/js/JSScriptEnginePerfTests.java b/apct-tests/perftests/rubidium/src/android/rubidium/js/JSScriptEnginePerfTests.java
index ba15796..fc3738c 100644
--- a/apct-tests/perftests/rubidium/src/android/rubidium/js/JSScriptEnginePerfTests.java
+++ b/apct-tests/perftests/rubidium/src/android/rubidium/js/JSScriptEnginePerfTests.java
@@ -53,6 +53,7 @@
 import com.android.adservices.service.adselection.AdWithBidArgumentUtil;
 import com.android.adservices.service.adselection.CustomAudienceBiddingSignalsArgumentUtil;
 import com.android.adservices.service.adselection.CustomAudienceScoringSignalsArgumentUtil;
+import com.android.adservices.service.common.NoOpRetryStrategyImpl;
 import com.android.adservices.service.js.IsolateSettings;
 import com.android.adservices.service.js.JSScriptArgument;
 import com.android.adservices.service.js.JSScriptArrayArgument;
@@ -411,7 +412,8 @@
                 jsScript,
                 args,
                 functionName,
-                IsolateSettings.forMaxHeapSizeEnforcementDisabled());
+                IsolateSettings.forMaxHeapSizeEnforcementDisabled(),
+                new NoOpRetryStrategyImpl());
         result.addListener(resultLatch::countDown, sExecutorService);
         return result;
     }
@@ -430,7 +432,8 @@
                 wasmScript,
                 args,
                 functionName,
-                IsolateSettings.forMaxHeapSizeEnforcementDisabled());
+                IsolateSettings.forMaxHeapSizeEnforcementDisabled(),
+                new NoOpRetryStrategyImpl());
         result.addListener(resultLatch::countDown, sExecutorService);
         return result;
     }
diff --git a/apex/jobscheduler/service/Android.bp b/apex/jobscheduler/service/Android.bp
index 5586295..0104ee1 100644
--- a/apex/jobscheduler/service/Android.bp
+++ b/apex/jobscheduler/service/Android.bp
@@ -21,6 +21,7 @@
 
     libs: [
         "app-compat-annotations",
+        "error_prone_annotations",
         "framework",
         "services.core",
         "unsupportedappusage",
diff --git a/apex/jobscheduler/service/aconfig/alarm.aconfig b/apex/jobscheduler/service/aconfig/alarm.aconfig
index 3b9b4e7..bb0f3cb 100644
--- a/apex/jobscheduler/service/aconfig/alarm.aconfig
+++ b/apex/jobscheduler/service/aconfig/alarm.aconfig
@@ -9,3 +9,10 @@
       purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "start_user_before_scheduled_alarms"
+    namespace: "multiuser"
+    description: "Persist list of users with alarms scheduled and wakeup stopped users before alarms are due"
+    bug: "314907186"
+}
diff --git a/apex/jobscheduler/service/aconfig/device_idle.aconfig b/apex/jobscheduler/service/aconfig/device_idle.aconfig
index fc24b30..e4cb5ad 100644
--- a/apex/jobscheduler/service/aconfig/device_idle.aconfig
+++ b/apex/jobscheduler/service/aconfig/device_idle.aconfig
@@ -4,5 +4,5 @@
     name: "disable_wakelocks_in_light_idle"
     namespace: "backstage_power"
     description: "Disable wakelocks for background apps while Light Device Idle is active"
-    bug: "299329948"
+    bug: "326607666"
 }
diff --git a/apex/jobscheduler/service/aconfig/job.aconfig b/apex/jobscheduler/service/aconfig/job.aconfig
index ef9ac73..5e6d377 100644
--- a/apex/jobscheduler/service/aconfig/job.aconfig
+++ b/apex/jobscheduler/service/aconfig/job.aconfig
@@ -4,7 +4,7 @@
     name: "batch_active_bucket_jobs"
     namespace: "backstage_power"
     description: "Include jobs in the ACTIVE bucket in the job batching effort. Don't let them run as freely as they're ready."
-    bug: "299329948"
+    bug: "326607666"
 }
 
 flag {
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index e728a2c..d0a1b02 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -183,6 +183,9 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.zone.ZoneOffsetTransition;
+import java.time.zone.ZoneRules;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -194,6 +197,7 @@
 import java.util.TimeZone;
 import java.util.TreeSet;
 import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
 
 /**
@@ -234,8 +238,12 @@
 
     private static final long TEMPORARY_QUOTA_DURATION = INTERVAL_DAY;
 
-    // System property read on some device configurations to initialize time properly.
+    // System properties read on some device configurations to initialize time properly and
+    // perform DST transitions at the bootloader level.
     private static final String TIMEOFFSET_PROPERTY = "persist.sys.time.offset";
+    private static final String DST_TRANSITION_PROPERTY = "persist.sys.time.dst_transition";
+    private static final String DST_OFFSET_PROPERTY = "persist.sys.time.dst_offset";
+
 
     private final Intent mBackgroundIntent
             = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
@@ -2200,6 +2208,19 @@
 
             final int gmtOffset = newZone.getOffset(mInjector.getCurrentTimeMillis());
             SystemProperties.set(TIMEOFFSET_PROPERTY, String.valueOf(gmtOffset));
+
+            final ZoneRules rules = newZone.toZoneId().getRules();
+            final ZoneOffsetTransition transition = rules.nextTransition(Instant.now());
+            if (null != transition) {
+                // Get the offset between the time after the DST transition and before.
+                final long transitionOffset = TimeUnit.SECONDS.toMillis((
+                        transition.getOffsetAfter().getTotalSeconds()
+                        - transition.getOffsetBefore().getTotalSeconds()));
+                // Time when the next DST transition is programmed.
+                final long nextTransition = TimeUnit.SECONDS.toMillis(transition.toEpochSecond());
+                SystemProperties.set(DST_TRANSITION_PROPERTY, String.valueOf(nextTransition));
+                SystemProperties.set(DST_OFFSET_PROPERTY, String.valueOf(transitionOffset));
+            }
         }
 
         // Clear the default time zone in the system server process. This forces the next call
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index 1f5b83c..c1add03 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -458,13 +458,21 @@
     libs: ["stub-annotations"],
 }
 
+java_defaults {
+    name: "android-non-updatable_everything_from_text_defaults",
+    defaults: [
+        "android-non-updatable_from_text_defaults",
+    ],
+    stubs_type: "everything",
+}
+
 java_api_library {
     name: "android-non-updatable.stubs.from-text",
     api_surface: "public",
     api_contributions: [
         "api-stubs-docs-non-updatable.api.contribution",
     ],
-    defaults: ["android-non-updatable_from_text_defaults"],
+    defaults: ["android-non-updatable_everything_from_text_defaults"],
     full_api_surface_stub: "android_stubs_current.from-text",
 }
 
@@ -475,7 +483,7 @@
         "api-stubs-docs-non-updatable.api.contribution",
         "system-api-stubs-docs-non-updatable.api.contribution",
     ],
-    defaults: ["android-non-updatable_from_text_defaults"],
+    defaults: ["android-non-updatable_everything_from_text_defaults"],
     full_api_surface_stub: "android_system_stubs_current.from-text",
 }
 
@@ -487,7 +495,7 @@
         "system-api-stubs-docs-non-updatable.api.contribution",
         "test-api-stubs-docs-non-updatable.api.contribution",
     ],
-    defaults: ["android-non-updatable_from_text_defaults"],
+    defaults: ["android-non-updatable_everything_from_text_defaults"],
     full_api_surface_stub: "android_test_stubs_current.from-text",
 }
 
@@ -499,7 +507,7 @@
         "system-api-stubs-docs-non-updatable.api.contribution",
         "module-lib-api-stubs-docs-non-updatable.api.contribution",
     ],
-    defaults: ["android-non-updatable_from_text_defaults"],
+    defaults: ["android-non-updatable_everything_from_text_defaults"],
     full_api_surface_stub: "android_module_lib_stubs_current_full.from-text",
 }
 
@@ -515,7 +523,7 @@
         "test-api-stubs-docs-non-updatable.api.contribution",
         "module-lib-api-stubs-docs-non-updatable.api.contribution",
     ],
-    defaults: ["android-non-updatable_from_text_defaults"],
+    defaults: ["android-non-updatable_everything_from_text_defaults"],
     full_api_surface_stub: "android_test_module_lib_stubs_current.from-text",
 
     // This module is only used for hiddenapi, and other modules should not
@@ -836,6 +844,7 @@
     ],
     visibility: ["//visibility:public"],
     enable_validation: false,
+    stubs_type: "everything",
 }
 
 java_api_library {
@@ -852,6 +861,7 @@
     ],
     visibility: ["//visibility:public"],
     enable_validation: false,
+    stubs_type: "everything",
 }
 
 java_api_library {
@@ -870,6 +880,7 @@
     ],
     visibility: ["//visibility:public"],
     enable_validation: false,
+    stubs_type: "everything",
 }
 
 java_api_library {
@@ -888,6 +899,7 @@
         "system-api-stubs-docs-non-updatable.api.contribution",
     ],
     enable_validation: false,
+    stubs_type: "everything",
 }
 
 java_api_library {
@@ -908,6 +920,7 @@
     ],
     visibility: ["//visibility:public"],
     enable_validation: false,
+    stubs_type: "everything",
 }
 
 java_api_library {
@@ -922,6 +935,7 @@
     ],
     visibility: ["//visibility:public"],
     enable_validation: false,
+    stubs_type: "everything",
 }
 
 java_api_library {
@@ -947,6 +961,7 @@
         "//visibility:private",
     ],
     enable_validation: false,
+    stubs_type: "everything",
 }
 
 java_api_library {
@@ -964,6 +979,7 @@
     ],
     visibility: ["//visibility:public"],
     enable_validation: false,
+    stubs_type: "everything",
 }
 
 ////////////////////////////////////////////////////////////////////////
diff --git a/boot/Android.bp b/boot/Android.bp
index cdfa7c80..f60bb9e 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -31,6 +31,7 @@
         "car_bootclasspath_fragment",
         "nfc_apex_bootclasspath_fragment",
         "release_crashrecovery_module",
+        "release_package_profiling_module",
     ],
     properties: [
         "fragments",
@@ -122,10 +123,6 @@
             module: "com.android.permission-bootclasspath-fragment",
         },
         {
-            apex: "com.android.profiling",
-            module: "com.android.profiling-bootclasspath-fragment",
-        },
-        {
             apex: "com.android.scheduling",
             module: "com.android.scheduling-bootclasspath-fragment",
         },
@@ -179,6 +176,15 @@
                 },
             ],
         },
+        release_package_profiling_module: {
+            fragments: [
+                // only used if profiling is enabled.
+                {
+                    apex: "com.android.profiling",
+                    module: "com.android.profiling-bootclasspath-fragment",
+                },
+            ],
+        },
     },
 
     // Additional information needed by hidden api processing.
diff --git a/cmds/idmap2/tests/FabricatedOverlayTests.cpp b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
index 6b1c7e8..15109d9 100644
--- a/cmds/idmap2/tests/FabricatedOverlayTests.cpp
+++ b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
@@ -144,7 +144,7 @@
               "com.example.target:string/string1", Res_value::TYPE_STRING, "foobar", "")
           .Build();
   ASSERT_TRUE(overlay);
-  TemporaryFile tf;
+  TempFrroFile tf;
   std::ofstream out(tf.path);
   ASSERT_TRUE((*overlay).ToBinaryStream(out));
   out.close();
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index a384305..c85619c 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -274,7 +274,7 @@
                   .Build();
 
   ASSERT_TRUE(frro);
-  TemporaryFile tf;
+  TempFrroFile tf;
   std::ofstream out(tf.path);
   ASSERT_TRUE((*frro).ToBinaryStream(out));
   out.close();
@@ -467,9 +467,9 @@
 TEST(IdmapTests, IdmapHeaderIsUpToDate) {
   fclose(stderr);  // silence expected warnings from libandroidfw
 
-  const std::string target_apk_path = kIdmapRawTargetPath;
-  const std::string overlay_apk_path = kIdmapRawOverlayPath;
-  const std::string overlay_name = kIdmapRawOverlayName;
+  const std::string target_apk_path {kIdmapRawTargetPath};
+  const std::string overlay_apk_path {kIdmapRawOverlayPath};
+  const std::string overlay_name {kIdmapRawOverlayName};
   const PolicyBitmask policies = kIdmapRawDataPolicies;
   const uint32_t target_crc = kIdmapRawDataTargetCrc;
   const uint32_t overlay_crc = kIdmapRawOverlayCrc;
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index db44c23..1d22553 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -217,7 +217,7 @@
                   .Build();
 
   ASSERT_TRUE(frro);
-  TemporaryFile tf;
+  TempFrroFile tf;
   std::ofstream out(tf.path);
   ASSERT_TRUE((*frro).ToBinaryStream(out));
   out.close();
diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h
index cdc0b8f..bf01c32 100644
--- a/cmds/idmap2/tests/TestHelpers.h
+++ b/cmds/idmap2/tests/TestHelpers.h
@@ -17,11 +17,15 @@
 #ifndef IDMAP2_TESTS_TESTHELPERS_H_
 #define IDMAP2_TESTS_TESTHELPERS_H_
 
+#include <stdio.h>
 #include <string>
+#include <string_view>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
+#include "android-base/file.h"
+
 namespace android::idmap2 {
 
 const unsigned char kIdmapRawData[] = {
@@ -197,12 +201,23 @@
 const unsigned int kIdmapRawDataTargetCrc = 0x1234;
 const unsigned int kIdmapRawOverlayCrc = 0x5678;
 const unsigned int kIdmapRawDataPolicies = 0x11;
-inline const std::string kIdmapRawTargetPath = "targetX.apk";
-inline const std::string kIdmapRawOverlayPath = "overlayX.apk";
-inline const std::string kIdmapRawOverlayName = "OverlayName";
+inline const std::string_view kIdmapRawTargetPath = "targetX.apk";
+inline const std::string_view kIdmapRawOverlayPath = "overlayX.apk";
+inline const std::string_view kIdmapRawOverlayName = "OverlayName";
 
 std::string GetTestDataPath();
 
+class TempFrroFile : public TemporaryFile {
+public:
+  TempFrroFile() {
+    std::string new_path = path;
+    new_path += ".frro";
+    ::rename(path, new_path.c_str());
+    const auto new_len = new_path.copy(path, sizeof(path) - 1);
+    path[new_len] = '\0';
+  }
+};
+
 class Idmap2Tests : public testing::Test {
  protected:
   void SetUp() override {
diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
index a7560b2..12b79f4 100644
--- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
@@ -23,8 +23,6 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.sysprop.InitProperties;
 
 public class PowerCommand extends Svc.Command {
     private static final int FORCE_SUSPEND_DELAY_DEFAULT_MILLIS = 0;
@@ -142,12 +140,10 @@
     // Check if remote exception is benign during shutdown. Pm can be killed
     // before system server during shutdown, so remote exception can be ignored
     // if it is already in shutdown flow.
+    // sys.powerctl is no longer set to avoid a possible DOS attack (see
+    // bionic/libc/bionic/system_property_set.cpp) so we have no real way of knowing if a
+    // remote exception is real or simply because pm is killed (b/318323013)
+    // So we simply do not display anything.
     private void maybeLogRemoteException(String msg) {
-        String powerProp = SystemProperties.get("sys.powerctl");
-        // Also check if userspace reboot is ongoing, since in case of userspace reboot value of the
-        // sys.powerctl property will be reset.
-        if (powerProp.isEmpty() && !InitProperties.userspace_reboot_in_progress().orElse(false)) {
-            System.err.println(msg);
-        }
     }
 }
diff --git a/core/api/current.txt b/core/api/current.txt
index 386396c..62980ed 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -203,7 +203,7 @@
     field public static final String MANAGE_DEVICE_POLICY_SYSTEM_APPS = "android.permission.MANAGE_DEVICE_POLICY_SYSTEM_APPS";
     field public static final String MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS = "android.permission.MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS";
     field public static final String MANAGE_DEVICE_POLICY_SYSTEM_UPDATES = "android.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES";
-    field @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled") public static final String MANAGE_DEVICE_POLICY_THREAD_NETWORK = "android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK";
+    field @FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled") public static final String MANAGE_DEVICE_POLICY_THREAD_NETWORK = "android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK";
     field public static final String MANAGE_DEVICE_POLICY_TIME = "android.permission.MANAGE_DEVICE_POLICY_TIME";
     field public static final String MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING = "android.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING";
     field public static final String MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER = "android.permission.MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER";
@@ -691,7 +691,6 @@
     field public static final int defaultHeight = 16844021; // 0x10104f5
     field @FlaggedApi("android.content.res.default_locale") public static final int defaultLocale;
     field public static final int defaultToDeviceProtectedStorage = 16844036; // 0x1010504
-    field @FlaggedApi("android.nfc.Flags.FLAG_OBSERVE_MODE") public static final int defaultToObserveMode;
     field public static final int defaultValue = 16843245; // 0x10101ed
     field public static final int defaultWidth = 16844020; // 0x10104f4
     field public static final int delay = 16843212; // 0x10101cc
@@ -1501,6 +1500,7 @@
     field public static final int shortcutId = 16844072; // 0x1010528
     field public static final int shortcutLongLabel = 16844074; // 0x101052a
     field public static final int shortcutShortLabel = 16844073; // 0x1010529
+    field @FlaggedApi("android.nfc.Flags.FLAG_OBSERVE_MODE") public static final int shouldDefaultToObserveMode;
     field public static final int shouldDisableView = 16843246; // 0x10101ee
     field public static final int shouldUseDefaultUnfoldTransition = 16844364; // 0x101064c
     field public static final int showAsAction = 16843481; // 0x10102d9
@@ -3350,7 +3350,6 @@
     method @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks") public void attachAccessibilityOverlayToWindow(int, @NonNull android.view.SurfaceControl, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
     method public boolean clearCache();
     method public boolean clearCachedSubtree(@NonNull android.view.accessibility.AccessibilityNodeInfo);
-    method @FlaggedApi("android.view.accessibility.braille_display_hid") public void clearTestBrailleDisplayController();
     method public final void disableSelf();
     method public final boolean dispatchGesture(@NonNull android.accessibilityservice.GestureDescription, @Nullable android.accessibilityservice.AccessibilityService.GestureResultCallback, @Nullable android.os.Handler);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -3386,7 +3385,6 @@
     method public boolean setCacheEnabled(boolean);
     method public void setGestureDetectionPassthroughRegion(int, @NonNull android.graphics.Region);
     method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
-    method @FlaggedApi("android.view.accessibility.braille_display_hid") public void setTestBrailleDisplayController(@NonNull android.accessibilityservice.BrailleDisplayController);
     method public void setTouchExplorationPassthroughRegion(int, @NonNull android.graphics.Region);
     method public void takeScreenshot(int, @NonNull java.util.concurrent.Executor, @NonNull android.accessibilityservice.AccessibilityService.TakeScreenshotCallback);
     method public void takeScreenshotOfWindow(int, @NonNull java.util.concurrent.Executor, @NonNull android.accessibilityservice.AccessibilityService.TakeScreenshotCallback);
@@ -13121,7 +13119,6 @@
     field public static final String FEATURE_CAMERA_LEVEL_FULL = "android.hardware.camera.level.full";
     field public static final String FEATURE_CANT_SAVE_STATE = "android.software.cant_save_state";
     field public static final String FEATURE_COMPANION_DEVICE_SETUP = "android.software.companion_device_setup";
-    field @FlaggedApi("android.view.inputmethod.concurrent_input_methods") public static final String FEATURE_CONCURRENT_INPUT_METHODS = "android.software.concurrent_input_methods";
     field @Deprecated public static final String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
     field public static final String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
     field public static final String FEATURE_CONTROLS = "android.software.controls";
@@ -13218,7 +13215,7 @@
     field public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio.access";
     field public static final String FEATURE_TELEPHONY_SUBSCRIPTION = "android.hardware.telephony.subscription";
     field @Deprecated public static final String FEATURE_TELEVISION = "android.hardware.type.television";
-    field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network";
+    field @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network";
     field public static final String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen";
     field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch";
     field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT = "android.hardware.touchscreen.multitouch.distinct";
@@ -13510,7 +13507,7 @@
     field public static final int FLAG_USE_APP_ZYGOTE = 8; // 0x8
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CAMERA}, anyOf={android.Manifest.permission.CAMERA}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 64; // 0x40
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE}, anyOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.CHANGE_NETWORK_STATE, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, android.Manifest.permission.NFC, android.Manifest.permission.TRANSMIT_IR, android.Manifest.permission.UWB_RANGING}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10
-    field @Deprecated @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1
+    field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_HEALTH}, anyOf={android.Manifest.permission.ACTIVITY_RECOGNITION, android.Manifest.permission.BODY_SENSORS, android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS}) public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 256; // 0x100
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_LOCATION}, anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 8; // 0x8
     field public static final int FOREGROUND_SERVICE_TYPE_MANIFEST = -1; // 0xffffffff
@@ -34086,7 +34083,7 @@
     field @FlaggedApi("android.app.admin.flags.esim_management_enabled") public static final String DISALLOW_SIM_GLOBALLY = "no_sim_globally";
     field public static final String DISALLOW_SMS = "no_sms";
     field public static final String DISALLOW_SYSTEM_ERROR_DIALOGS = "no_system_error_dialogs";
-    field @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled") public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
+    field @FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled") public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
     field public static final String DISALLOW_ULTRA_WIDEBAND_RADIO = "no_ultra_wideband_radio";
     field public static final String DISALLOW_UNIFIED_PASSWORD = "no_unified_password";
     field public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
@@ -35817,54 +35814,6 @@
     field public static final String LONGITUDE = "longitude";
   }
 
-  @FlaggedApi("android.provider.user_keys") public final class ContactKeysManager {
-    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.ContactKey> getAllContactKeys(@NonNull String);
-    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.SelfKey> getAllSelfKeys();
-    method @Nullable @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public android.provider.ContactKeysManager.ContactKey getContactKey(@NonNull String, @NonNull String, @NonNull String);
-    method public static int getMaxKeySizeBytes();
-    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.ContactKey> getOwnerContactKeys(@NonNull String);
-    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.SelfKey> getOwnerSelfKeys();
-    method @Nullable @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public android.provider.ContactKeysManager.SelfKey getSelfKey(@NonNull String, @NonNull String);
-    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean removeContactKey(@NonNull String, @NonNull String, @NonNull String);
-    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean removeSelfKey(@NonNull String, @NonNull String);
-    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateContactKeyLocalVerificationState(@NonNull String, @NonNull String, @NonNull String, int);
-    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateContactKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, int);
-    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public void updateOrInsertContactKey(@NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
-    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateOrInsertSelfKey(@NonNull String, @NonNull String, @NonNull byte[]);
-    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateSelfKeyRemoteVerificationState(@NonNull String, @NonNull String, int);
-    field public static final int VERIFICATION_STATE_UNVERIFIED = 0; // 0x0
-    field public static final int VERIFICATION_STATE_VERIFICATION_FAILED = 1; // 0x1
-    field public static final int VERIFICATION_STATE_VERIFIED = 2; // 0x2
-  }
-
-  public static final class ContactKeysManager.ContactKey implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public String getAccountId();
-    method @Nullable public String getDeviceId();
-    method @Nullable public String getDisplayName();
-    method @Nullable public String getEmailAddress();
-    method @Nullable public byte[] getKeyValue();
-    method public int getLocalVerificationState();
-    method @NonNull public String getOwnerPackageName();
-    method @Nullable public String getPhoneNumber();
-    method public int getRemoteVerificationState();
-    method public long getTimeUpdated();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.provider.ContactKeysManager.ContactKey> CREATOR;
-  }
-
-  public static final class ContactKeysManager.SelfKey implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public String getAccountId();
-    method @Nullable public String getDeviceId();
-    method @Nullable public byte[] getKeyValue();
-    method @NonNull public String getOwnerPackageName();
-    method public int getRemoteVerificationState();
-    method public long getTimeUpdated();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.provider.ContactKeysManager.SelfKey> CREATOR;
-  }
-
   @Deprecated public class Contacts {
     field @Deprecated public static final String AUTHORITY = "contacts";
     field @Deprecated public static final android.net.Uri CONTENT_URI;
@@ -37165,6 +37114,54 @@
     method public final int update(android.net.Uri, android.content.ContentValues, String, String[]);
   }
 
+  @FlaggedApi("android.provider.user_keys") public final class E2eeContactKeysManager {
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.E2eeContactKeysManager.E2eeContactKey> getAllE2eeContactKeys(@NonNull String);
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.E2eeContactKeysManager.E2eeSelfKey> getAllE2eeSelfKeys();
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public android.provider.E2eeContactKeysManager.E2eeContactKey getE2eeContactKey(@NonNull String, @NonNull String, @NonNull String);
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public android.provider.E2eeContactKeysManager.E2eeSelfKey getE2eeSelfKey(@NonNull String, @NonNull String);
+    method public static int getMaxKeySizeBytes();
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.E2eeContactKeysManager.E2eeContactKey> getOwnerE2eeContactKeys(@NonNull String);
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.E2eeContactKeysManager.E2eeSelfKey> getOwnerE2eeSelfKeys();
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean removeE2eeContactKey(@NonNull String, @NonNull String, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean removeE2eeSelfKey(@NonNull String, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateE2eeContactKeyLocalVerificationState(@NonNull String, @NonNull String, @NonNull String, int);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateE2eeContactKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, int);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateE2eeSelfKeyRemoteVerificationState(@NonNull String, @NonNull String, int);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public void updateOrInsertE2eeContactKey(@NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateOrInsertE2eeSelfKey(@NonNull String, @NonNull String, @NonNull byte[]);
+    field public static final int VERIFICATION_STATE_UNVERIFIED = 0; // 0x0
+    field public static final int VERIFICATION_STATE_VERIFICATION_FAILED = 1; // 0x1
+    field public static final int VERIFICATION_STATE_VERIFIED = 2; // 0x2
+  }
+
+  public static final class E2eeContactKeysManager.E2eeContactKey implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public String getAccountId();
+    method @Nullable public String getDeviceId();
+    method @Nullable public String getDisplayName();
+    method @Nullable public String getEmailAddress();
+    method @Nullable public byte[] getKeyValue();
+    method public int getLocalVerificationState();
+    method @NonNull public String getOwnerPackageName();
+    method @Nullable public String getPhoneNumber();
+    method public int getRemoteVerificationState();
+    method public long getTimeUpdated();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.provider.E2eeContactKeysManager.E2eeContactKey> CREATOR;
+  }
+
+  public static final class E2eeContactKeysManager.E2eeSelfKey implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public String getAccountId();
+    method @Nullable public String getDeviceId();
+    method @Nullable public byte[] getKeyValue();
+    method @NonNull public String getOwnerPackageName();
+    method public int getRemoteVerificationState();
+    method public long getTimeUpdated();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.provider.E2eeContactKeysManager.E2eeSelfKey> CREATOR;
+  }
+
   @Deprecated public final class FontRequest {
     ctor @Deprecated public FontRequest(@NonNull String, @NonNull String, @NonNull String);
     ctor @Deprecated public FontRequest(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.List<java.util.List<byte[]>>);
@@ -39801,6 +39798,7 @@
     method @Deprecated public boolean isInsideSecureHardware();
     method public boolean isInvalidatedByBiometricEnrollment();
     method public boolean isTrustedUserPresenceRequired();
+    method @FlaggedApi("android.security.keyinfo_unlocked_device_required") public boolean isUnlockedDeviceRequired();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
     method public boolean isUserAuthenticationValidWhileOnBody();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index d9b5d56..afb796b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -327,7 +327,7 @@
     field public static final String RECOVER_KEYSTORE = "android.permission.RECOVER_KEYSTORE";
     field public static final String REGISTER_CALL_PROVIDER = "android.permission.REGISTER_CALL_PROVIDER";
     field public static final String REGISTER_CONNECTION_MANAGER = "android.permission.REGISTER_CONNECTION_MANAGER";
-    field @FlaggedApi("com.android.net.flags.register_nsd_offload_engine") public static final String REGISTER_NSD_OFFLOAD_ENGINE = "android.permission.REGISTER_NSD_OFFLOAD_ENGINE";
+    field @FlaggedApi("android.net.platform.flags.register_nsd_offload_engine") public static final String REGISTER_NSD_OFFLOAD_ENGINE = "android.permission.REGISTER_NSD_OFFLOAD_ENGINE";
     field public static final String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION";
     field public static final String REGISTER_STATS_PULL_ATOM = "android.permission.REGISTER_STATS_PULL_ATOM";
     field public static final String REMOTE_DISPLAY_PROVIDER = "android.permission.REMOTE_DISPLAY_PROVIDER";
@@ -388,7 +388,7 @@
     field public static final String SYSTEM_APPLICATION_OVERLAY = "android.permission.SYSTEM_APPLICATION_OVERLAY";
     field public static final String SYSTEM_CAMERA = "android.permission.SYSTEM_CAMERA";
     field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
-    field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String THREAD_NETWORK_PRIVILEGED = "android.permission.THREAD_NETWORK_PRIVILEGED";
+    field @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") public static final String THREAD_NETWORK_PRIVILEGED = "android.permission.THREAD_NETWORK_PRIVILEGED";
     field public static final String TIS_EXTENSION_INTERFACE = "android.permission.TIS_EXTENSION_INTERFACE";
     field public static final String TOGGLE_AUTOMOTIVE_PROJECTION = "android.permission.TOGGLE_AUTOMOTIVE_PROJECTION";
     field public static final String TRIGGER_LOST_MODE = "android.permission.TRIGGER_LOST_MODE";
@@ -1647,14 +1647,12 @@
     method public int getDensityLevel();
     method @NonNull public java.time.Instant getEndTime();
     method public int getEventType();
-    method @FlaggedApi("android.app.ambient_heart_rate") @IntRange(from=0xffffffff) public int getRatePerMinute();
     method @NonNull public java.time.Instant getStartTime();
     method @NonNull public android.os.PersistableBundle getVendorData();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.ambientcontext.AmbientContextEvent> CREATOR;
     field public static final int EVENT_BACK_DOUBLE_TAP = 3; // 0x3
     field public static final int EVENT_COUGH = 1; // 0x1
-    field @FlaggedApi("android.app.ambient_heart_rate") public static final int EVENT_HEART_RATE = 4; // 0x4
     field public static final int EVENT_SNORE = 2; // 0x2
     field public static final int EVENT_UNKNOWN = 0; // 0x0
     field public static final int EVENT_VENDOR_WEARABLE_START = 100000; // 0x186a0
@@ -1665,7 +1663,6 @@
     field public static final int LEVEL_MEDIUM_HIGH = 4; // 0x4
     field public static final int LEVEL_MEDIUM_LOW = 2; // 0x2
     field public static final int LEVEL_UNKNOWN = 0; // 0x0
-    field @FlaggedApi("android.app.ambient_heart_rate") public static final int RATE_PER_MINUTE_UNKNOWN = -1; // 0xffffffff
   }
 
   public static final class AmbientContextEvent.Builder {
@@ -1675,7 +1672,6 @@
     method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setDensityLevel(int);
     method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setEndTime(@NonNull java.time.Instant);
     method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setEventType(int);
-    method @FlaggedApi("android.app.ambient_heart_rate") @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setRatePerMinute(@IntRange(from=0xffffffff) int);
     method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setStartTime(@NonNull java.time.Instant);
     method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setVendorData(@NonNull android.os.PersistableBundle);
   }
@@ -3787,7 +3783,7 @@
     field public static final String SYSTEM_CONFIG_SERVICE = "system_config";
     field public static final String SYSTEM_UPDATE_SERVICE = "system_update";
     field public static final String TETHERING_SERVICE = "tethering";
-    field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String THREAD_NETWORK_SERVICE = "thread_network";
+    field @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") public static final String THREAD_NETWORK_SERVICE = "thread_network";
     field public static final String TIME_MANAGER_SERVICE = "time_manager";
     field public static final String TRANSLATION_MANAGER_SERVICE = "translation";
     field public static final String UI_TRANSLATION_SERVICE = "ui_translation";
@@ -10422,7 +10418,6 @@
   @FlaggedApi("android.nfc.enable_nfc_mainline") public final class ApduServiceInfo implements android.os.Parcelable {
     ctor @FlaggedApi("android.nfc.enable_nfc_mainline") public ApduServiceInfo(@NonNull android.content.pm.PackageManager, @NonNull android.content.pm.ResolveInfo, boolean) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopFilter(@NonNull String, boolean);
-    method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean defaultToObserveMode();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public int describeContents();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dump(@NonNull android.os.ParcelFileDescriptor, @NonNull java.io.PrintWriter, @NonNull String[]);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dumpDebug(@NonNull android.util.proto.ProtoOutputStream);
@@ -10452,9 +10447,10 @@
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean requiresUnlock();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void resetOffHostSecureElement();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setCategoryOtherServiceEnabled(boolean);
-    method @FlaggedApi("android.nfc.nfc_observe_mode") public void setDefaultToObserveMode(boolean);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setDynamicAidGroup(@NonNull android.nfc.cardemulation.AidGroup);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setOffHostSecureElement(@NonNull String);
+    method @FlaggedApi("android.nfc.nfc_observe_mode") public void setShouldDefaultToObserveMode(boolean);
+    method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean shouldDefaultToObserveMode();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void writeToParcel(@NonNull android.os.Parcel, int);
     field @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.ApduServiceInfo> CREATOR;
   }
@@ -10762,7 +10758,7 @@
     method public final double readDouble();
     method public final java.util.ArrayList<java.lang.Double> readDoubleVector();
     method public final android.os.HwBlob readEmbeddedBuffer(long, long, long, boolean);
-    method @NonNull @Nullable public final android.os.HidlMemory readEmbeddedHidlMemory(long, long, long);
+    method @NonNull public final android.os.HidlMemory readEmbeddedHidlMemory(long, long, long);
     method @Nullable public final android.os.NativeHandle readEmbeddedNativeHandle(long, long);
     method public final float readFloat();
     method public final java.util.ArrayList<java.lang.Float> readFloatVector();
@@ -11708,12 +11704,6 @@
     field public static final int ERROR_UNKNOWN = 0; // 0x0
   }
 
-  @FlaggedApi("android.provider.user_keys") public final class ContactKeysManager {
-    method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateContactKeyLocalVerificationState(@NonNull String, @NonNull String, @NonNull String, @NonNull String, int);
-    method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateContactKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, @NonNull String, int);
-    method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateSelfKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, int);
-  }
-
   @Deprecated public static final class ContactsContract.MetadataSync implements android.provider.BaseColumns android.provider.ContactsContract.MetadataSyncColumns {
     field @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata";
     field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_metadata";
@@ -11771,6 +11761,12 @@
     field public static final int FLAG_REMOVABLE_USB = 524288; // 0x80000
   }
 
+  @FlaggedApi("android.provider.user_keys") public final class E2eeContactKeysManager {
+    method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateE2eeContactKeyLocalVerificationState(@NonNull String, @NonNull String, @NonNull String, @NonNull String, int);
+    method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateE2eeContactKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, @NonNull String, int);
+    method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateE2eeSelfKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, int);
+  }
+
   public abstract class SearchIndexableData {
     ctor public SearchIndexableData();
     ctor public SearchIndexableData(android.content.Context);
@@ -12967,9 +12963,22 @@
     method public abstract void onGetReadOnlyFeatureFileDescriptorMap(@NonNull android.app.ondeviceintelligence.Feature, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,android.os.ParcelFileDescriptor>>);
     method public abstract void onGetVersion(@NonNull java.util.function.LongConsumer);
     method public abstract void onListFeatures(@NonNull android.os.OutcomeReceiver<java.util.List<android.app.ondeviceintelligence.Feature>,android.app.ondeviceintelligence.OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException>);
+    method public final void updateProcessingState(@NonNull android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.os.PersistableBundle,android.service.ondeviceintelligence.OnDeviceIntelligenceService.OnDeviceUpdateProcessingException>);
     field public static final String SERVICE_INTERFACE = "android.service.ondeviceintelligence.OnDeviceIntelligenceService";
   }
 
+  public static class OnDeviceIntelligenceService.OnDeviceIntelligenceServiceException extends java.lang.Exception {
+    ctor public OnDeviceIntelligenceService.OnDeviceIntelligenceServiceException(int);
+    ctor public OnDeviceIntelligenceService.OnDeviceIntelligenceServiceException(int, @NonNull String);
+    method public int getErrorCode();
+  }
+
+  public static class OnDeviceIntelligenceService.OnDeviceUpdateProcessingException extends android.service.ondeviceintelligence.OnDeviceIntelligenceService.OnDeviceIntelligenceServiceException {
+    ctor public OnDeviceIntelligenceService.OnDeviceUpdateProcessingException(int);
+    ctor public OnDeviceIntelligenceService.OnDeviceUpdateProcessingException(int, @NonNull String);
+    field public static final int PROCESSING_UPDATE_STATUS_CONNECTION_FAILED = 1; // 0x1
+  }
+
   @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public abstract class OnDeviceTrustedInferenceService extends android.app.Service {
     ctor public OnDeviceTrustedInferenceService();
     method public final void fetchFeatureFileInputStreamMap(@NonNull android.app.ondeviceintelligence.Feature, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.io.FileInputStream>>);
@@ -12977,6 +12986,7 @@
     method @NonNull public abstract void onCountTokens(@NonNull android.app.ondeviceintelligence.Feature, @NonNull android.app.ondeviceintelligence.Content, @Nullable android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver<java.lang.Long,android.app.ondeviceintelligence.OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException>);
     method @NonNull public abstract void onProcessRequest(@NonNull android.app.ondeviceintelligence.Feature, @NonNull android.app.ondeviceintelligence.Content, int, @Nullable android.os.CancellationSignal, @Nullable android.app.ondeviceintelligence.ProcessingSignal, @NonNull android.os.OutcomeReceiver<android.app.ondeviceintelligence.Content,android.app.ondeviceintelligence.OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException>);
     method @NonNull public abstract void onProcessRequestStreaming(@NonNull android.app.ondeviceintelligence.Feature, @NonNull android.app.ondeviceintelligence.Content, int, @Nullable android.os.CancellationSignal, @Nullable android.app.ondeviceintelligence.ProcessingSignal, @NonNull android.app.ondeviceintelligence.StreamingResponseReceiver<android.app.ondeviceintelligence.Content,android.app.ondeviceintelligence.Content,android.app.ondeviceintelligence.OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException>);
+    method public abstract void onUpdateProcessingState(@NonNull android.os.Bundle, @NonNull android.os.OutcomeReceiver<android.os.PersistableBundle,android.service.ondeviceintelligence.OnDeviceIntelligenceService.OnDeviceUpdateProcessingException>);
     method public final java.io.FileInputStream openFileInput(@NonNull String) throws java.io.FileNotFoundException;
     method public final void openFileInputAsync(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.io.FileInputStream>) throws java.io.FileNotFoundException;
     field public static final String SERVICE_INTERFACE = "android.service.ondeviceintelligence.OnDeviceTrustedInferenceService";
@@ -15320,12 +15330,12 @@
     method @Deprecated public boolean getDataEnabled(int);
     method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getDefaultRespondViaMessageApplication();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceSoftwareVersion(int);
-    method @FlaggedApi("android.permission.flags.get_emergency_role_holder_api_enabled") @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getEmergencyAssistancePackage();
+    method @FlaggedApi("android.permission.flags.get_emergency_role_holder_api_enabled") @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getEmergencyAssistancePackageName();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEmergencyNumberDbVersion();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst();
-    method @FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies") @Nullable @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_LAST_KNOWN_CELL_ID}) public android.telephony.CellIdentity getLastKnownCellIdentity();
+    method @FlaggedApi("com.android.server.telecom.flags.get_last_known_cell_identity") @Nullable @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_LAST_KNOWN_CELL_ID}) public android.telephony.CellIdentity getLastKnownCellIdentity();
     method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Map<java.lang.Integer,java.lang.Integer> getLogicalToPhysicalSlotMapping();
     method public int getMaxNumberOfSimultaneouslyActiveSims();
     method public static long getMaxNumberVerificationTimeoutMillis();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index cdf232c..6fb6b0d 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -251,6 +251,7 @@
     method @RequiresPermission("android.permission.MANAGE_APPOPS") public void getHistoricalOpsFromDiskRaw(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
     method public static int getNumOps();
     method public boolean isOperationActive(int, int, String);
+    method public int noteOpNoThrow(int, @NonNull android.content.AttributionSource, @Nullable String);
     method @RequiresPermission("android.permission.MANAGE_APPOPS") public void offsetHistory(long);
     method public static String opToPermission(int);
     method public static int permissionToOpCode(String);
@@ -316,9 +317,6 @@
   }
 
   public class ComponentOptions {
-    field public static final int MODE_BACKGROUND_ACTIVITY_START_ALLOWED = 1; // 0x1
-    field public static final int MODE_BACKGROUND_ACTIVITY_START_DENIED = 2; // 0x2
-    field public static final int MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED = 0; // 0x0
   }
 
   public class DownloadManager {
@@ -1368,7 +1366,7 @@
   }
 
   @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public class IntentFactory {
-    method @NonNull public static android.content.Intent createCancelUiIntent(@NonNull android.os.IBinder, boolean, @NonNull String);
+    method @NonNull public static android.content.Intent createCancelUiIntent(@NonNull android.content.Context, @NonNull android.os.IBinder, boolean, @NonNull String);
     method @NonNull public static android.content.Intent createCredentialSelectorIntent(@NonNull android.content.Context, @NonNull android.credentials.selection.RequestInfo, @NonNull java.util.ArrayList<android.credentials.selection.ProviderData>, @NonNull java.util.ArrayList<android.credentials.selection.DisabledProviderData>, @NonNull android.os.ResultReceiver);
   }
 
@@ -2033,41 +2031,6 @@
     method public android.media.PlaybackParams setAudioStretchMode(int);
   }
 
-  @FlaggedApi("android.os.vibrator.haptics_customization_enabled") public final class RingtoneSelection {
-    method @NonNull public static android.media.RingtoneSelection fromUri(@Nullable android.net.Uri, int);
-    method public int getSoundSource();
-    method @Nullable public android.net.Uri getSoundUri();
-    method public int getVibrationSource();
-    method @Nullable public android.net.Uri getVibrationUri();
-    method public static boolean isRingtoneSelectionUri(@Nullable android.net.Uri);
-    method @NonNull public android.net.Uri toUri();
-    field public static final String DEFAULT_SELECTION_URI_STRING = "content://media/ringtone";
-    field public static final int FROM_URI_RINGTONE_SELECTION_ONLY = 3; // 0x3
-    field public static final int FROM_URI_RINGTONE_SELECTION_OR_SOUND = 1; // 0x1
-    field public static final int FROM_URI_RINGTONE_SELECTION_OR_VIBRATION = 2; // 0x2
-    field public static final int SOUND_SOURCE_OFF = 1; // 0x1
-    field public static final int SOUND_SOURCE_SYSTEM_DEFAULT = 3; // 0x3
-    field public static final int SOUND_SOURCE_UNSPECIFIED = 0; // 0x0
-    field public static final int SOUND_SOURCE_URI = 2; // 0x2
-    field public static final int VIBRATION_SOURCE_APPLICATION_DEFAULT = 4; // 0x4
-    field public static final int VIBRATION_SOURCE_AUDIO_CHANNEL = 10; // 0xa
-    field public static final int VIBRATION_SOURCE_HAPTIC_GENERATOR = 11; // 0xb
-    field public static final int VIBRATION_SOURCE_OFF = 1; // 0x1
-    field public static final int VIBRATION_SOURCE_SYSTEM_DEFAULT = 3; // 0x3
-    field public static final int VIBRATION_SOURCE_UNSPECIFIED = 0; // 0x0
-    field public static final int VIBRATION_SOURCE_URI = 2; // 0x2
-  }
-
-  @FlaggedApi("android.os.vibrator.haptics_customization_enabled") public static final class RingtoneSelection.Builder {
-    ctor public RingtoneSelection.Builder();
-    ctor public RingtoneSelection.Builder(@NonNull android.media.RingtoneSelection);
-    method @NonNull public android.media.RingtoneSelection build();
-    method @NonNull public android.media.RingtoneSelection.Builder setSoundSource(int);
-    method @NonNull public android.media.RingtoneSelection.Builder setSoundSource(@NonNull android.net.Uri);
-    method @NonNull public android.media.RingtoneSelection.Builder setVibrationSource(int);
-    method @NonNull public android.media.RingtoneSelection.Builder setVibrationSource(@NonNull android.net.Uri);
-  }
-
   public static final class VolumeShaper.Configuration.Builder {
     method @NonNull public android.media.VolumeShaper.Configuration.Builder setOptionFlags(int);
   }
@@ -3966,6 +3929,7 @@
   }
 
   public final class InputMethodInfo implements android.os.Parcelable {
+    ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, @NonNull String, boolean, @NonNull String);
     ctor @FlaggedApi("android.view.inputmethod.connectionless_handwriting") public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, @NonNull String, boolean, boolean, @NonNull String);
     ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, int);
     field public static final int COMPONENT_NAME_MAX_LENGTH = 1000; // 0x3e8
@@ -3980,6 +3944,7 @@
     method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodListAsUser(int);
     method public boolean hasActiveInputConnection(@Nullable android.view.View);
     method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean hasPendingImeVisibilityRequests();
+    method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public void hideSoftInputFromServerForTest();
     method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isCurrentRootView(@NonNull android.view.View);
     method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isInputMethodPickerShown();
     method @FlaggedApi("android.view.inputmethod.imm_userhandle_hostsidetests") @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public boolean isStylusHandwritingAvailableAsUser(@NonNull android.os.UserHandle);
diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index 658ddbf..685ea63 100644
--- a/core/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
@@ -2055,14 +2055,8 @@
     New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_DEFAULT
 UnflaggedApi: android.media.RingtoneSelection#SOUND_SOURCE_OFF:
     New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_OFF
-UnflaggedApi: android.media.RingtoneSelection#SOUND_SOURCE_SYSTEM_DEFAULT:
-    New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_SYSTEM_DEFAULT
-UnflaggedApi: android.media.RingtoneSelection#SOUND_SOURCE_UNSPECIFIED:
-    New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_UNSPECIFIED
 UnflaggedApi: android.media.RingtoneSelection#SOUND_SOURCE_URI:
     New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.SOUND_SOURCE_URI
-UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_APPLICATION_DEFAULT:
-    New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_APPLICATION_DEFAULT
 UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_APPLICATION_PROVIDED:
     New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_APPLICATION_PROVIDED
 UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_AUDIO_CHANNEL:
@@ -2073,10 +2067,6 @@
     New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_HAPTIC_GENERATOR
 UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_OFF:
     New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_OFF
-UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_SYSTEM_DEFAULT:
-    New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_SYSTEM_DEFAULT
-UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_UNSPECIFIED:
-    New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_UNSPECIFIED
 UnflaggedApi: android.media.RingtoneSelection#VIBRATION_SOURCE_URI:
     New API must be flagged with @FlaggedApi: field android.media.RingtoneSelection.VIBRATION_SOURCE_URI
 UnflaggedApi: android.media.RingtoneSelection#fromUri(android.net.Uri, int):
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 34b8a87..ab1c9a4 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -528,14 +528,10 @@
     ],
 }
 
-// common protolog sources without classes that rely on Android SDK
-filegroup {
-    name: "protolog-common-no-android-src",
+java_library {
+    name: "protolog-group",
     srcs: [
-        ":protolog-common-src",
-    ],
-    exclude_srcs: [
-        "com/android/internal/protolog/common/ProtoLog.java",
+        "com/android/internal/protolog/common/IProtoLogGroup.java",
     ],
 }
 
@@ -548,13 +544,20 @@
     ],
 }
 
+filegroup {
+    name: "protolog-impl",
+    srcs: [
+        "com/android/internal/protolog/ProtoLogImpl.java",
+    ],
+}
+
 java_library {
     name: "protolog-lib",
     platform_apis: true,
     srcs: [
         "com/android/internal/protolog/ProtoLogImpl.java",
         "com/android/internal/protolog/ProtoLogViewerConfigReader.java",
-        ":protolog-common-src",
+        ":perfetto_trace_javastream_protos",
     ],
 }
 
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 42c3272..d70fa19 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -81,7 +81,6 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.Collections;
 import java.util.List;
-import java.util.Objects;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 import java.util.function.IntConsumer;
@@ -853,7 +852,6 @@
     private final SparseArray<AccessibilityButtonController> mAccessibilityButtonControllers =
             new SparseArray<>(0);
     private BrailleDisplayController mBrailleDisplayController;
-    private BrailleDisplayController mTestBrailleDisplayController;
 
     private int mGestureStatusCallbackSequence;
 
@@ -3650,46 +3648,10 @@
     public BrailleDisplayController getBrailleDisplayController() {
         BrailleDisplayController.checkApiFlagIsEnabled();
         synchronized (mLock) {
-            if (mTestBrailleDisplayController != null) {
-                return mTestBrailleDisplayController;
-            }
-
             if (mBrailleDisplayController == null) {
                 mBrailleDisplayController = new BrailleDisplayControllerImpl(this, mLock);
             }
             return mBrailleDisplayController;
         }
     }
-
-    /**
-     * Set the {@link BrailleDisplayController} implementation that will be returned by
-     * {@link #getBrailleDisplayController}, to allow this accessibility service to test its
-     * interaction with BrailleDisplayController without requiring a real Braille display.
-     *
-     * <p>For full test fidelity, ensure that this test-only implementation follows the same
-     * behavior specified in the documentation for {@link BrailleDisplayController}, including
-     * thrown exceptions.
-     *
-     * @param controller A test-only implementation of {@link BrailleDisplayController}.
-     */
-    @FlaggedApi(android.view.accessibility.Flags.FLAG_BRAILLE_DISPLAY_HID)
-    public void setTestBrailleDisplayController(@NonNull BrailleDisplayController controller) {
-        BrailleDisplayController.checkApiFlagIsEnabled();
-        Objects.requireNonNull(controller);
-        synchronized (mLock) {
-            mTestBrailleDisplayController = controller;
-        }
-    }
-
-    /**
-     * Clears the {@link BrailleDisplayController} previously set by
-     * {@link #setTestBrailleDisplayController}.
-     */
-    @FlaggedApi(android.view.accessibility.Flags.FLAG_BRAILLE_DISPLAY_HID)
-    public void clearTestBrailleDisplayController() {
-        BrailleDisplayController.checkApiFlagIsEnabled();
-        synchronized (mLock) {
-            mTestBrailleDisplayController = null;
-        }
-    }
 }
diff --git a/core/java/android/accessibilityservice/BrailleDisplayControllerImpl.java b/core/java/android/accessibilityservice/BrailleDisplayControllerImpl.java
index cac1dc4..f1df336 100644
--- a/core/java/android/accessibilityservice/BrailleDisplayControllerImpl.java
+++ b/core/java/android/accessibilityservice/BrailleDisplayControllerImpl.java
@@ -25,9 +25,11 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.view.accessibility.AccessibilityInteractionClient;
 import android.view.accessibility.Flags;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FunctionalUtils;
 
 import java.io.IOException;
@@ -36,24 +38,46 @@
 
 /**
  * Default implementation of {@link BrailleDisplayController}.
+ *
+ * @hide
  */
 // BrailleDisplayControllerImpl is not an API, but it implements BrailleDisplayController APIs.
 // This @FlaggedApi annotation tells the linter that this method delegates API checks to its
 // callers.
 @FlaggedApi(Flags.FLAG_BRAILLE_DISPLAY_HID)
-final class BrailleDisplayControllerImpl implements BrailleDisplayController {
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+public final class BrailleDisplayControllerImpl implements BrailleDisplayController {
 
     private final AccessibilityService mAccessibilityService;
     private final Object mLock;
+    private final boolean mIsHidrawSupported;
 
     private IBrailleDisplayConnection mBrailleDisplayConnection;
     private Executor mCallbackExecutor;
     private BrailleDisplayCallback mCallback;
 
+    /**
+     * Read-only property that returns whether HIDRAW access is supported on this device.
+     *
+     * <p>Defaults to true.
+     *
+     * <p>Device manufacturers without HIDRAW kernel support can set this to false in
+     * the device's product makefile.
+     */
+    private static final boolean IS_HIDRAW_SUPPORTED = SystemProperties.getBoolean(
+            "ro.accessibility.support_hidraw", true);
+
     BrailleDisplayControllerImpl(AccessibilityService accessibilityService,
             Object lock) {
+        this(accessibilityService, lock, IS_HIDRAW_SUPPORTED);
+    }
+
+    @VisibleForTesting
+    public BrailleDisplayControllerImpl(AccessibilityService accessibilityService,
+            Object lock, boolean isHidrawSupported) {
         mAccessibilityService = accessibilityService;
         mLock = lock;
+        mIsHidrawSupported = isHidrawSupported;
     }
 
     @Override
@@ -113,6 +137,11 @@
                     createConnection,
             @NonNull Executor callbackExecutor, @NonNull BrailleDisplayCallback callback) {
         BrailleDisplayController.checkApiFlagIsEnabled();
+        if (!mIsHidrawSupported) {
+            callbackExecutor.execute(() -> callback.onConnectionFailed(
+                    BrailleDisplayCallback.FLAG_ERROR_CANNOT_ACCESS));
+            return;
+        }
         if (isConnected()) {
             throw new IllegalStateException(
                     "This service already has a connected Braille display");
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 57c67be..63cafdc 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -9601,9 +9601,9 @@
      * Specifies whether the activities below this one in the task can also start other activities
      * or finish the task.
      * <p>
-     * Starting from Target SDK Level {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, apps
-     * are blocked from starting new activities or finishing their task unless the top activity of
-     * such task belong to the same UID for security reasons.
+     * Starting from Target SDK Level {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}, apps
+     * may be blocked from starting new activities or finishing their task unless the top activity
+     * of such task belong to the same UID for security reasons.
      * <p>
      * Setting this flag to {@code true} will allow the launching app to ignore the restriction if
      * this activity is on top. Apps matching the UID of this activity are always exempt.
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 2a2c5f0..e094ac6 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -93,15 +93,30 @@
      */
     public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
 
-    /** No explicit value chosen. The system will decide whether to grant privileges. */
-    public static final int MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED =
-            ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
-    /** Allow the {@link PendingIntent} to use the background activity start privileges. */
-    public static final int MODE_BACKGROUND_ACTIVITY_START_ALLOWED =
-            ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
-    /** Deny the {@link PendingIntent} to use the background activity start privileges. */
-    public static final int MODE_BACKGROUND_ACTIVITY_START_DENIED =
-            ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
+    /** Enumeration of background activity start modes.
+     *
+     * These define if an app wants to grant it's background activity start privileges to a
+     * {@link PendingIntent}.
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"MODE_BACKGROUND_ACTIVITY_START_"}, value = {
+            MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED,
+            MODE_BACKGROUND_ACTIVITY_START_ALLOWED,
+            MODE_BACKGROUND_ACTIVITY_START_DENIED})
+    public @interface BackgroundActivityStartMode {}
+    /**
+     * No explicit value chosen. The system will decide whether to grant privileges.
+     */
+    public static final int MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED = 0;
+    /**
+     * Allow the {@link PendingIntent} to use the background activity start privileges.
+     */
+    public static final int MODE_BACKGROUND_ACTIVITY_START_ALLOWED = 1;
+    /**
+     * Deny the {@link PendingIntent} to use the background activity start privileges.
+     */
+    public static final int MODE_BACKGROUND_ACTIVITY_START_DENIED = 2;
 
     /**
      * The package name that created the options.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ae556c9..1d39186 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -40,6 +40,7 @@
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
 import static com.android.internal.os.SafeZipPathValidatorCallback.VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL;
 import static com.android.sdksandbox.flags.Flags.sandboxActivitySdkBasedContext;
+import static com.android.window.flags.Flags.activityWindowInfoFlag;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -63,6 +64,7 @@
 import android.app.servertransaction.ActivityRelaunchItem;
 import android.app.servertransaction.ActivityResultItem;
 import android.app.servertransaction.ClientTransaction;
+import android.app.servertransaction.ClientTransactionListenerController;
 import android.app.servertransaction.DestroyActivityItem;
 import android.app.servertransaction.PauseActivityItem;
 import android.app.servertransaction.PendingTransactionActions;
@@ -211,6 +213,7 @@
 import android.view.translation.TranslationSpec;
 import android.view.translation.UiTranslationSpec;
 import android.webkit.WebView;
+import android.window.ActivityWindowInfo;
 import android.window.ITaskFragmentOrganizer;
 import android.window.SizeConfigurationBuckets;
 import android.window.SplashScreen;
@@ -603,6 +606,11 @@
         boolean hideForNow;
         Configuration createdConfig;
         Configuration overrideConfig;
+        @NonNull
+        private ActivityWindowInfo mActivityWindowInfo;
+        @Nullable
+        private ActivityWindowInfo mLastReportedActivityWindowInfo;
+
         // Used for consolidating configs before sending on to Activity.
         private final Configuration tmpConfig = new Configuration();
         // Callback used for updating activity override config and camera compat control state.
@@ -670,7 +678,8 @@
                 List<ReferrerIntent> pendingNewIntents, SceneTransitionInfo sceneTransitionInfo,
                 boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client,
                 IBinder assistToken, IBinder shareableActivityToken, boolean launchedFromBubble,
-                IBinder taskFragmentToken, IBinder initialCallerInfoAccessToken) {
+                IBinder taskFragmentToken, IBinder initialCallerInfoAccessToken,
+                ActivityWindowInfo activityWindowInfo) {
             this.token = token;
             this.assistToken = assistToken;
             this.shareableActivityToken = shareableActivityToken;
@@ -691,6 +700,7 @@
             mSceneTransitionInfo = sceneTransitionInfo;
             mLaunchedFromBubble = launchedFromBubble;
             mTaskFragmentToken = taskFragmentToken;
+            mActivityWindowInfo = activityWindowInfo;
             init();
         }
 
@@ -711,7 +721,7 @@
                     }
                     activity.mMainThread.handleActivityConfigurationChanged(
                             ActivityClientRecord.this, overrideConfig, newDisplayId,
-                            false /* alwaysReportChange */);
+                            mActivityWindowInfo, false /* alwaysReportChange */);
                 }
 
                 @Override
@@ -779,6 +789,11 @@
             return activity != null && activity.mVisibleFromServer;
         }
 
+        @NonNull
+        public ActivityWindowInfo getActivityWindowInfo() {
+            return mActivityWindowInfo;
+        }
+
         public String toString() {
             ComponentName componentName = intent != null ? intent.getComponent() : null;
             return "ActivityRecord{"
@@ -4169,6 +4184,9 @@
                 pendingActions.setRestoreInstanceState(true);
                 pendingActions.setCallOnPostCreate(true);
             }
+
+            // Trigger ActivityWindowInfo callback if first launch or change from relaunch.
+            handleActivityWindowInfoChanged(r);
         } else {
             // If there was an error, for any reason, tell the activity manager to stop us.
             ActivityClient.getInstance().finishActivity(r.token, Activity.RESULT_CANCELED,
@@ -4547,7 +4565,7 @@
     private void schedulePauseWithUserLeavingHint(ActivityClientRecord r) {
         final ClientTransaction transaction = ClientTransaction.obtain(mAppThread);
         final PauseActivityItem pauseActivityItem = PauseActivityItem.obtain(r.token,
-                r.activity.isFinishing(), /* userLeaving */ true, r.activity.mConfigChangeFlags,
+                r.activity.isFinishing(), /* userLeaving */ true,
                 /* dontReport */ false, /* autoEnteringPip */ false);
         transaction.addTransactionItem(pauseActivityItem);
         executeTransaction(transaction);
@@ -5421,13 +5439,12 @@
 
     @Override
     public void handlePauseActivity(ActivityClientRecord r, boolean finished, boolean userLeaving,
-            int configChanges, boolean autoEnteringPip, PendingTransactionActions pendingActions,
+            boolean autoEnteringPip, PendingTransactionActions pendingActions,
             String reason) {
         if (userLeaving) {
             performUserLeavingActivity(r);
         }
 
-        r.activity.mConfigChangeFlags |= configChanges;
         if (autoEnteringPip) {
             // Set mIsInPictureInPictureMode earlier in case of auto-enter-pip, see also
             // {@link Activity#enterPictureInPictureMode(PictureInPictureParams)}.
@@ -5676,9 +5693,8 @@
     }
 
     @Override
-    public void handleStopActivity(ActivityClientRecord r, int configChanges,
+    public void handleStopActivity(ActivityClientRecord r,
             PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) {
-        r.activity.mConfigChangeFlags |= configChanges;
 
         final StopInfo stopInfo = new StopInfo();
         performStopActivityInner(r, stopInfo, true /* saveState */, finalStateRequest,
@@ -5848,11 +5864,10 @@
 
     /** Core implementation of activity destroy call. */
     void performDestroyActivity(ActivityClientRecord r, boolean finishing,
-            int configChanges, boolean getNonConfigInstance, String reason) {
+            boolean getNonConfigInstance, String reason) {
         Class<? extends Activity> activityClass;
         if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
         activityClass = r.activity.getClass();
-        r.activity.mConfigChangeFlags |= configChanges;
         if (finishing) {
             r.activity.mFinished = true;
         }
@@ -5917,9 +5932,9 @@
     }
 
     @Override
-    public void handleDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges,
+    public void handleDestroyActivity(ActivityClientRecord r, boolean finishing,
             boolean getNonConfigInstance, String reason) {
-        performDestroyActivity(r, finishing, configChanges, getNonConfigInstance, reason);
+        performDestroyActivity(r, finishing, getNonConfigInstance, reason);
         cleanUpPendingRemoveWindows(r, finishing);
         WindowManager wm = r.activity.getWindowManager();
         View v = r.activity.mDecor;
@@ -5987,9 +6002,11 @@
     }
 
     @Override
-    public ActivityClientRecord prepareRelaunchActivity(IBinder token,
-            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
-            int configChanges, MergedConfiguration config, boolean preserveWindow) {
+    public ActivityClientRecord prepareRelaunchActivity(@NonNull IBinder token,
+            @Nullable List<ResultInfo> pendingResults,
+            @Nullable List<ReferrerIntent> pendingNewIntents, int configChanges,
+            @NonNull MergedConfiguration config, boolean preserveWindow,
+            @NonNull ActivityWindowInfo activityWindowInfo) {
         ActivityClientRecord target = null;
         boolean scheduleRelaunch = false;
 
@@ -6030,14 +6047,15 @@
             target.createdConfig = config.getGlobalConfiguration();
             target.overrideConfig = config.getOverrideConfiguration();
             target.pendingConfigChanges |= configChanges;
+            target.mActivityWindowInfo = activityWindowInfo;
         }
 
         return scheduleRelaunch ? target : null;
     }
 
     @Override
-    public void handleRelaunchActivity(ActivityClientRecord tmp,
-            PendingTransactionActions pendingActions) {
+    public void handleRelaunchActivity(@NonNull ActivityClientRecord tmp,
+            @NonNull PendingTransactionActions pendingActions) {
         // If we are getting ready to gc after going to the background, well
         // we are back active so skip it.
         unscheduleGcIdler();
@@ -6116,8 +6134,9 @@
 
         r.activity.mChangingConfigurations = true;
 
-        handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents,
-                pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity");
+        handleRelaunchActivityInner(r, tmp.pendingResults, tmp.pendingIntents,
+                pendingActions, tmp.startsNotResumed, tmp.overrideConfig, tmp.mActivityWindowInfo,
+                "handleRelaunchActivity");
     }
 
     void scheduleRelaunchActivity(IBinder token) {
@@ -6172,7 +6191,8 @@
                 r.overrideConfig);
         final ActivityRelaunchItem activityRelaunchItem = ActivityRelaunchItem.obtain(
                 r.token, null /* pendingResults */, null /* pendingIntents */,
-                0 /* configChanges */, mergedConfiguration, r.mPreserveWindow);
+                0 /* configChanges */, mergedConfiguration, r.mPreserveWindow,
+                r.getActivityWindowInfo());
         // Make sure to match the existing lifecycle state in the end of the transaction.
         final ActivityLifecycleItem lifecycleRequest =
                 TransactionExecutorHelper.getLifecycleRequestForCurrentState(r);
@@ -6183,10 +6203,12 @@
         executeTransaction(transaction);
     }
 
-    private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges,
-            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents,
-            PendingTransactionActions pendingActions, boolean startsNotResumed,
-            Configuration overrideConfig, String reason) {
+    private void handleRelaunchActivityInner(@NonNull ActivityClientRecord r,
+            @Nullable List<ResultInfo> pendingResults,
+            @Nullable List<ReferrerIntent> pendingIntents,
+            @NonNull PendingTransactionActions pendingActions, boolean startsNotResumed,
+            @NonNull Configuration overrideConfig, @NonNull ActivityWindowInfo activityWindowInfo,
+            @NonNull String reason) {
         // Preserve last used intent, it may be set from Activity#setIntent().
         final Intent customIntent = r.activity.mIntent;
         // Need to ensure state is saved.
@@ -6197,7 +6219,7 @@
             callActivityOnStop(r, true /* saveState */, reason);
         }
 
-        handleDestroyActivity(r, false, configChanges, true, reason);
+        handleDestroyActivity(r, false /* finishing */, true /* getNonConfigInstance */, reason);
 
         r.activity = null;
         r.window = null;
@@ -6219,6 +6241,7 @@
         }
         r.startsNotResumed = startsNotResumed;
         r.overrideConfig = overrideConfig;
+        r.mActivityWindowInfo = activityWindowInfo;
 
         handleLaunchActivity(r, pendingActions, mLastReportedDeviceId, customIntent);
     }
@@ -6640,11 +6663,12 @@
     /**
      * Sets the supplied {@code overrideConfig} as pending for the {@code token}. Calling
      * this method prevents any calls to
-     * {@link #handleActivityConfigurationChanged(ActivityClientRecord, Configuration, int)} from
-     * processing any configurations older than {@code overrideConfig}.
+     * {@link #handleActivityConfigurationChanged(ActivityClientRecord, Configuration, int,
+     * ActivityWindowInfo)} from processing any configurations older than {@code overrideConfig}.
      */
     @Override
-    public void updatePendingActivityConfiguration(IBinder token, Configuration overrideConfig) {
+    public void updatePendingActivityConfiguration(@NonNull IBinder token,
+            @NonNull Configuration overrideConfig) {
         synchronized (mPendingOverrideConfigs) {
             final Configuration pendingOverrideConfig = mPendingOverrideConfigs.get(token);
             if (pendingOverrideConfig != null
@@ -6661,9 +6685,10 @@
     }
 
     @Override
-    public void handleActivityConfigurationChanged(ActivityClientRecord r,
-            @NonNull Configuration overrideConfig, int displayId) {
-        handleActivityConfigurationChanged(r, overrideConfig, displayId,
+    public void handleActivityConfigurationChanged(@NonNull ActivityClientRecord r,
+            @NonNull Configuration overrideConfig, int displayId,
+            @NonNull ActivityWindowInfo activityWindowInfo) {
+        handleActivityConfigurationChanged(r, overrideConfig, displayId, activityWindowInfo,
                 // This is the only place that uses alwaysReportChange=true. The entry point should
                 // be from ActivityConfigurationChangeItem or MoveToDisplayItem, so the server side
                 // has confirmed the activity should handle the configuration instead of relaunch.
@@ -6681,9 +6706,11 @@
      * @param overrideConfig Activity override config.
      * @param displayId Id of the display where activity was moved to, -1 if there was no move and
      *                  value didn't change.
+     * @param activityWindowInfo the window info of the given activity.
      */
-    void handleActivityConfigurationChanged(ActivityClientRecord r,
-            @NonNull Configuration overrideConfig, int displayId, boolean alwaysReportChange) {
+    void handleActivityConfigurationChanged(@NonNull ActivityClientRecord r,
+            @NonNull Configuration overrideConfig, int displayId,
+            @NonNull ActivityWindowInfo activityWindowInfo, boolean alwaysReportChange) {
         synchronized (mPendingOverrideConfigs) {
             final Configuration pendingOverrideConfig = mPendingOverrideConfigs.get(r.token);
             if (overrideConfig.isOtherSeqNewer(pendingOverrideConfig)) {
@@ -6716,6 +6743,8 @@
 
         // Perform updates.
         r.overrideConfig = overrideConfig;
+        r.mActivityWindowInfo = activityWindowInfo;
+
         final ViewRootImpl viewRoot = r.activity.mDecor != null
             ? r.activity.mDecor.getViewRootImpl() : null;
 
@@ -6738,6 +6767,22 @@
             viewRoot.updateConfiguration(displayId);
         }
         mSomeActivitiesChanged = true;
+
+        // Trigger ActivityWindowInfo callback if changed.
+        handleActivityWindowInfoChanged(r);
+    }
+
+    private void handleActivityWindowInfoChanged(@NonNull ActivityClientRecord r) {
+        if (!activityWindowInfoFlag()) {
+            return;
+        }
+        if (r.mActivityWindowInfo == null
+                || r.mActivityWindowInfo.equals(r.mLastReportedActivityWindowInfo)) {
+            return;
+        }
+        r.mLastReportedActivityWindowInfo = r.mActivityWindowInfo;
+        ClientTransactionListenerController.getInstance().onActivityWindowInfoChanged(r.token,
+                r.mActivityWindowInfo);
     }
 
     final void handleProfilerControl(boolean start, ProfilerInfo profilerInfo, int profileType) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 39900a0..2afc78c 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -7800,7 +7800,7 @@
         }
         final List<AppOpsManager.PackageOps> result;
         try {
-            result =  mService.getPackagesForOpsForDevice(opCodes, persistentDeviceId);
+            result = mService.getPackagesForOpsForDevice(opCodes, persistentDeviceId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -8272,14 +8272,24 @@
                 cb = new IAppOpsCallback.Stub() {
                     public void opChanged(int op, int uid, String packageName,
                             String persistentDeviceId) {
-                        if (callback instanceof OnOpChangedInternalListener) {
-                            ((OnOpChangedInternalListener)callback).onOpChanged(op, packageName,
-                                persistentDeviceId);
-                        }
-                        if (sAppOpInfos[op].name != null) {
-
-                            callback.onOpChanged(sAppOpInfos[op].name, packageName,
-                                    UserHandle.getUserId(uid), persistentDeviceId);
+                        if (Flags.deviceAwarePermissionApisEnabled()) {
+                            if (callback instanceof OnOpChangedInternalListener) {
+                                ((OnOpChangedInternalListener)callback).onOpChanged(op, packageName,
+                                        persistentDeviceId);
+                            }
+                            if (sAppOpInfos[op].name != null) {
+                                callback.onOpChanged(sAppOpInfos[op].name, packageName,
+                                        UserHandle.getUserId(uid), persistentDeviceId);
+                            }
+                        } else {
+                            if (callback instanceof OnOpChangedInternalListener) {
+                                ((OnOpChangedInternalListener) callback).onOpChanged(op,
+                                        packageName);
+                            }
+                            if (sAppOpInfos[op].name != null) {
+                                callback.onOpChanged(sAppOpInfos[op].name, packageName,
+                                        UserHandle.getUserId(uid));
+                            }
                         }
                     }
                 };
@@ -8940,6 +8950,8 @@
      *
      * @hide
      */
+    @TestApi
+    @SuppressLint("UnflaggedApi")
     public int noteOpNoThrow(int op, @NonNull AttributionSource attributionSource,
             @Nullable String message) {
         return noteOpNoThrow(op, attributionSource.getUid(), attributionSource.getPackageName(),
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index f6373d6..f6ec370 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -377,6 +377,9 @@
      * Sets the {@link ZenDeviceEffects} associated to this rule. Device effects specify changes to
      * the device behavior that should apply while the rule is active, but are not directly related
      * to suppressing notifications (for example: disabling always-on display).
+     *
+     * <p>When updating an existing rule via {@link NotificationManager#updateAutomaticZenRule},
+     * a {@code null} value here means the previous set of effects is retained.
      */
     @FlaggedApi(Flags.FLAG_MODES_API)
     public void setDeviceEffects(@Nullable ZenDeviceEffects deviceEffects) {
@@ -702,7 +705,15 @@
         }
 
         /**
-         * Sets the component (service or activity) that owns this rule.
+         * Sets the component name of the
+         * {@link android.service.notification.ConditionProviderService} that manages this rule
+         * (but note that {@link android.service.notification.ConditionProviderService} is
+         * deprecated in favor of using {@link NotificationManager#setAutomaticZenRuleState} to
+         * notify the system about the state of your rule).
+         *
+         * <p>This is exclusive with {@link #setConfigurationActivity}; rules where a configuration
+         * activity is set will not use the component set here to determine whether the rule
+         * should be active.
          */
         public @NonNull Builder setOwner(@Nullable ComponentName owner) {
             mOwner = owner;
@@ -740,6 +751,11 @@
          * information about this rule and/or allows them to configure it. This is required to be
          * non-null for rules that are not backed by a
          * {@link android.service.notification.ConditionProviderService}.
+         *
+         * <p>This is exclusive with {@link #setOwner}; rules where a configuration
+         * activity is set will not use the
+         * {@link android.service.notification.ConditionProviderService} supplied there to determine
+         * whether the rule should be active.
          */
         public @NonNull Builder setConfigurationActivity(
                 @Nullable ComponentName configurationActivity) {
@@ -749,6 +765,9 @@
 
         /**
          * Sets the zen policy.
+         *
+         * <p>When updating an existing rule via {@link NotificationManager#updateAutomaticZenRule},
+         * a {@code null} value here means the previous policy is retained.
          */
         public @NonNull Builder setZenPolicy(@Nullable ZenPolicy policy) {
             mPolicy = policy;
@@ -759,6 +778,9 @@
          * Sets the {@link ZenDeviceEffects} associated to this rule. Device effects specify changes
          * to the device behavior that should apply while the rule is active, but are not directly
          * related to suppressing notifications (for example: disabling always-on display).
+         *
+         * <p>When updating an existing rule via {@link NotificationManager#updateAutomaticZenRule},
+         * a {@code null} value here means the previous set of effects is retained.
          */
         @NonNull
         public Builder setDeviceEffects(@Nullable ZenDeviceEffects deviceEffects) {
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 1b5b0fc..60d622d 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import static android.app.ActivityOptions.BackgroundActivityStartMode;
+
 import android.annotation.CurrentTimeMillisLong;
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
@@ -1132,7 +1134,8 @@
     @SystemApi
     @NonNull
     @Override // to narrow down the return type
-    public BroadcastOptions setPendingIntentBackgroundActivityStartMode(int state) {
+    public BroadcastOptions setPendingIntentBackgroundActivityStartMode(
+            @BackgroundActivityStartMode int state) {
         super.setPendingIntentBackgroundActivityStartMode(state);
         return this;
     }
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index b300674..01153c9 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -30,6 +30,7 @@
 import android.os.IBinder;
 import android.util.MergedConfiguration;
 import android.view.SurfaceControl;
+import android.window.ActivityWindowInfo;
 import android.window.SplashScreenView.SplashScreenViewParcelable;
 import android.window.WindowContext;
 import android.window.WindowContextInfo;
@@ -113,11 +114,11 @@
 
     /** Destroy the activity. */
     public abstract void handleDestroyActivity(@NonNull ActivityClientRecord r, boolean finishing,
-            int configChanges, boolean getNonConfigInstance, String reason);
+            boolean getNonConfigInstance, String reason);
 
     /** Pause the activity. */
     public abstract void handlePauseActivity(@NonNull ActivityClientRecord r, boolean finished,
-            boolean userLeaving, int configChanges, boolean autoEnteringPip,
+            boolean userLeaving, boolean autoEnteringPip,
             PendingTransactionActions pendingActions, String reason);
 
     /**
@@ -145,14 +146,13 @@
     /**
      * Stop the activity.
      * @param r Target activity record.
-     * @param configChanges Activity configuration changes.
      * @param pendingActions Pending actions to be used on this or later stages of activity
      *                       transaction.
      * @param finalStateRequest Flag indicating if this call is handling final lifecycle state
      *                          request for a transaction.
      * @param reason Reason for performing this operation.
      */
-    public abstract void handleStopActivity(@NonNull ActivityClientRecord r, int configChanges,
+    public abstract void handleStopActivity(@NonNull ActivityClientRecord r,
             PendingTransactionActions pendingActions, boolean finalStateRequest, String reason);
 
     /** Report that activity was stopped to server. */
@@ -166,11 +166,12 @@
 
     /** Set pending activity configuration in case it will be updated by other transaction item. */
     public abstract void updatePendingActivityConfiguration(@NonNull IBinder token,
-            Configuration overrideConfig);
+            @NonNull Configuration overrideConfig);
 
     /** Deliver activity (override) configuration change. */
     public abstract void handleActivityConfigurationChanged(@NonNull ActivityClientRecord r,
-            Configuration overrideConfig, int displayId);
+            @NonNull Configuration overrideConfig, int displayId,
+            @NonNull ActivityWindowInfo activityWindowInfo);
 
     /** Deliver {@link android.window.WindowContextInfo} change. */
     public abstract void handleWindowContextInfoChanged(@NonNull IBinder clientToken,
@@ -232,12 +233,15 @@
      * @param config New configuration applied to the activity.
      * @param preserveWindow Whether the activity should try to reuse the window it created,
      *                        including the decor view after the relaunch.
+     * @param activityWindowInfo Window information about the relaunched Activity.
      * @return An initialized instance of {@link ActivityThread.ActivityClientRecord} to use during
      *         relaunch, or {@code null} if relaunch cancelled.
      */
-    public abstract ActivityClientRecord prepareRelaunchActivity(IBinder token,
-            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
-            int configChanges, MergedConfiguration config, boolean preserveWindow);
+    public abstract ActivityClientRecord prepareRelaunchActivity(@NonNull IBinder token,
+            @Nullable List<ResultInfo> pendingResults,
+            @Nullable List<ReferrerIntent> pendingNewIntents, int configChanges,
+            @NonNull MergedConfiguration config, boolean preserveWindow,
+            @NonNull ActivityWindowInfo activityWindowInfo);
 
     /**
      * Perform activity relaunch.
@@ -245,7 +249,7 @@
      * @param pendingActions Pending actions to be used on later stages of activity transaction.
      * */
     public abstract void handleRelaunchActivity(@NonNull ActivityClientRecord r,
-            PendingTransactionActions pendingActions);
+            @NonNull PendingTransactionActions pendingActions);
 
     /**
      * Report that relaunch request was handled.
diff --git a/core/java/android/app/ComponentOptions.java b/core/java/android/app/ComponentOptions.java
index ce16ddf..397477d 100644
--- a/core/java/android/app/ComponentOptions.java
+++ b/core/java/android/app/ComponentOptions.java
@@ -16,16 +16,17 @@
 
 package android.app;
 
-import android.annotation.IntDef;
+import static android.app.ActivityOptions.BackgroundActivityStartMode;
+import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
+import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
+import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
 import android.annotation.TestApi;
 import android.os.Bundle;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
 /**
  * Base class for {@link ActivityOptions} and {@link BroadcastOptions}.
  * @hide
@@ -56,32 +57,6 @@
     private @Nullable Boolean mPendingIntentBalAllowed = null;
     private boolean mPendingIntentBalAllowedByPermission = false;
 
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"MODE_BACKGROUND_ACTIVITY_START_"}, value = {
-            MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED,
-            MODE_BACKGROUND_ACTIVITY_START_ALLOWED,
-            MODE_BACKGROUND_ACTIVITY_START_DENIED})
-    public @interface BackgroundActivityStartMode {}
-    /**
-     * No explicit value chosen. The system will decide whether to grant privileges.
-     * @hide
-     */
-    @TestApi
-    public static final int MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED = 0;
-    /**
-     * Allow the {@link PendingIntent} to use the background activity start privileges.
-     * @hide
-     */
-    @TestApi
-    public static final int MODE_BACKGROUND_ACTIVITY_START_ALLOWED = 1;
-    /**
-     * Deny the {@link PendingIntent} to use the background activity start privileges.
-     * @hide
-     */
-    @TestApi
-    public static final int MODE_BACKGROUND_ACTIVITY_START_DENIED = 2;
-
     ComponentOptions() {
     }
 
diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java
index 7e06735..d1e517b 100644
--- a/core/java/android/app/ForegroundServiceTypePolicy.java
+++ b/core/java/android/app/ForegroundServiceTypePolicy.java
@@ -62,7 +62,6 @@
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbManager;
-import android.os.Build;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -128,14 +127,10 @@
      * The FGS type enforcement:
      * deprecating the {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_DATA_SYNC}.
      *
-     * <p>Starting a FGS with this type from apps with targetSdkVersion
-     * {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} or later will result in a warning
-     * in the log.
-     *
      * @hide
      */
     @ChangeId
-    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    @Disabled
     @Overridable
     public static final long FGS_TYPE_DATA_SYNC_DEPRECATION_CHANGE_ID = 255039210L;
 
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 1b19ecd..095cfc5 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -413,7 +413,7 @@
         if (localLOGV) Log.v(TAG, r.id + ": destroying");
         final ActivityClientRecord clientRecord = mActivityThread.getActivityClient(r);
         if (clientRecord != null) {
-            mActivityThread.performDestroyActivity(clientRecord, finish, 0 /* configChanges */,
+            mActivityThread.performDestroyActivity(clientRecord, finish,
                     false /* getNonConfigInstance */, "LocalActivityManager::performDestroy");
         }
         r.activity = null;
@@ -684,7 +684,7 @@
                 if (localLOGV) Log.v(TAG, r.id + ": no corresponding record");
                 continue;
             }
-            mActivityThread.performDestroyActivity(clientRecord, finishing, 0 /* configChanges */,
+            mActivityThread.performDestroyActivity(clientRecord, finishing,
                     false /* getNonConfigInstance */, "LocalActivityManager::dispatchDestroy");
         }
         mActivities.clear();
diff --git a/core/java/android/app/LocaleConfig.java b/core/java/android/app/LocaleConfig.java
index b2be27f..4a06f7d 100644
--- a/core/java/android/app/LocaleConfig.java
+++ b/core/java/android/app/LocaleConfig.java
@@ -248,7 +248,8 @@
     }
 
     /**
-     * Returns the default locale if specified, otherwise null
+     * Returns the locale the strings in values/strings.xml (the default strings in the directory
+     * with no locale qualifier) are in if specified, otherwise null
      *
      * @return The default Locale or null
      */
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 26f85f7..1129f9d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -7543,6 +7543,7 @@
         /**
          * @hide
          */
+        @SuppressWarnings("HiddenAbstractMethod")
         public abstract boolean areNotificationsVisiblyDifferent(Style other);
 
         /**
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 08c193f..d01626e 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -212,7 +212,7 @@
 import android.permission.PermissionManager;
 import android.print.IPrintManager;
 import android.print.PrintManager;
-import android.provider.ContactKeysManager;
+import android.provider.E2eeContactKeysManager;
 import android.safetycenter.SafetyCenterFrameworkInitializer;
 import android.scheduling.SchedulingFrameworkInitializer;
 import android.security.FileIntegrityManager;
@@ -1608,16 +1608,16 @@
                     }
                 });
 
-        registerService(Context.CONTACT_KEYS_SERVICE, ContactKeysManager.class,
-                new CachedServiceFetcher<ContactKeysManager>() {
+        registerService(Context.CONTACT_KEYS_SERVICE, E2eeContactKeysManager.class,
+                new CachedServiceFetcher<E2eeContactKeysManager>() {
                     @Override
-                    public ContactKeysManager createService(ContextImpl ctx)
+                    public E2eeContactKeysManager createService(ContextImpl ctx)
                             throws ServiceNotFoundException {
                         if (!android.provider.Flags.userKeys()) {
                             throw new ServiceNotFoundException(
                                     "ContactKeysManager is not supported");
                         }
-                        return new ContactKeysManager(ctx);
+                        return new E2eeContactKeysManager(ctx);
                     }});
 
         // DO NOT do a flag check like this unless the flag is read-only.
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 83fb393..02d6944 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -981,12 +981,12 @@
     /**
      * <strong> Important note: </strong>
      * <ul>
-     *     <li>Up to version S, this method requires the
+     *     <li>Up to Android 12, this method requires the
      *     {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.</li>
-     *     <li>Starting in T, directly accessing the wallpaper is not possible anymore,
+     *     <li>Starting in Android 13, directly accessing the wallpaper is not possible anymore,
      *     instead the default system wallpaper is returned
-     *     (some versions of T may throw a {@code SecurityException}).</li>
-     *     <li>From version U, this method should not be used
+     *     (some versions of Android 13 may throw a {@code SecurityException}).</li>
+     *     <li>From Android 14, this method should not be used
      *     and will always throw a {@code SecurityException}.</li>
      *     <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
      *     can still access the real wallpaper on all versions. </li>
@@ -1265,12 +1265,12 @@
     /**
      * <strong> Important note: </strong>
      * <ul>
-     *     <li>Up to version S, this method requires the
+     *     <li>Up to Android 12, this method requires the
      *     {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.</li>
-     *     <li>Starting in T, directly accessing the wallpaper is not possible anymore,
+     *     <li>Starting in Android 13, directly accessing the wallpaper is not possible anymore,
      *     instead the default system wallpaper is returned
-     *     (some versions of T may throw a {@code SecurityException}).</li>
-     *     <li>From version U, this method should not be used
+     *     (some versions of Android 13 may throw a {@code SecurityException}).</li>
+     *     <li>From Android 14, this method should not be used
      *     and will always throw a {@code SecurityException}.</li>
      *     <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
      *     can still access the real wallpaper on all versions. </li>
@@ -1318,12 +1318,12 @@
     /**
      * <strong> Important note: </strong>
      * <ul>
-     *     <li>Up to version S, this method requires the
+     *     <li>Up to Android 12, this method requires the
      *     {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.</li>
-     *     <li>Starting in T, directly accessing the wallpaper is not possible anymore,
+     *     <li>Starting in Android 13, directly accessing the wallpaper is not possible anymore,
      *     instead the default wallpaper is returned
-     *     (some versions of T may throw a {@code SecurityException}).</li>
-     *     <li>From version U, this method should not be used
+     *     (some versions of Android 13 may throw a {@code SecurityException}).</li>
+     *     <li>From Android 14, this method should not be used
      *     and will always throw a {@code SecurityException}.</li>
      *     <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
      *     can still access the real wallpaper on all versions. </li>
@@ -1677,12 +1677,12 @@
     /**
      * <strong> Important note: </strong>
      * <ul>
-     *     <li>Up to version S, this method requires the
+     *     <li>Up to Android 12, this method requires the
      *     {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.</li>
-     *     <li>Starting in T, directly accessing the wallpaper is not possible anymore,
+     *     <li>Starting in Android 13, directly accessing the wallpaper is not possible anymore,
      *     instead the default system wallpaper is returned
-     *     (some versions of T may throw a {@code SecurityException}).</li>
-     *     <li>From version U, this method should not be used
+     *     (some versions of Android 13 may throw a {@code SecurityException}).</li>
+     *     <li>From Android 14, this method should not be used
      *     and will always throw a {@code SecurityException}.</li>
      *     <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
      *     can still access the real wallpaper on all versions. </li>
@@ -1904,14 +1904,14 @@
      * caller doesn't have the appropriate permissions, this returns {@code null}.
      *
      * <p>
-     * Before Android U, this method requires the
+     * For devices running Android 13 or earlier, this method requires the
      * {@link android.Manifest.permission#QUERY_ALL_PACKAGES} permission.
      * </p>
      *
      * <p>
-     * Starting from Android U, in order to use this, apps should declare a {@code <queries>} tag
-     * with the action {@code "android.service.wallpaper.WallpaperService"}. Otherwise,
-     * this method will return {@code null} if the caller doesn't otherwise have
+     * For devices running Android 14 or later, in order to use this, apps should declare a
+     * {@code <queries>} tag with the action {@code "android.service.wallpaper.WallpaperService"}.
+     * Otherwise, this method will return {@code null} if the caller doesn't otherwise have
      * <a href="{@docRoot}training/package-visibility">visibility</a> of the wallpaper package.
      * </p>
      */
diff --git a/core/java/android/app/admin/AccountTypePolicyKey.java b/core/java/android/app/admin/AccountTypePolicyKey.java
index d81eb20..51f3137 100644
--- a/core/java/android/app/admin/AccountTypePolicyKey.java
+++ b/core/java/android/app/admin/AccountTypePolicyKey.java
@@ -19,12 +19,12 @@
 import static android.app.admin.PolicyUpdateReceiver.EXTRA_ACCOUNT_TYPE;
 import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_BUNDLE_KEY;
 import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_KEY;
-import static android.app.admin.flags.Flags.devicePolicySizeTrackingEnabled;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.app.admin.flags.Flags;
 import android.os.Bundle;
 import android.os.Parcel;
 
@@ -54,7 +54,7 @@
     @TestApi
     public AccountTypePolicyKey(@NonNull String key, @NonNull String accountType) {
         super(key);
-        if (devicePolicySizeTrackingEnabled()) {
+        if (Flags.devicePolicySizeTrackingInternalEnabled()) {
             PolicySizeVerifier.enforceMaxStringLength(accountType, "accountType");
         }
         mAccountType = Objects.requireNonNull((accountType));
diff --git a/core/java/android/app/admin/BundlePolicyValue.java b/core/java/android/app/admin/BundlePolicyValue.java
index cc5e75f..4f70604 100644
--- a/core/java/android/app/admin/BundlePolicyValue.java
+++ b/core/java/android/app/admin/BundlePolicyValue.java
@@ -16,10 +16,9 @@
 
 package android.app.admin;
 
-import static android.app.admin.flags.Flags.devicePolicySizeTrackingEnabled;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.admin.flags.Flags;
 import android.os.Bundle;
 import android.os.Parcel;
 
@@ -32,7 +31,7 @@
 
     public BundlePolicyValue(Bundle value) {
         super(value);
-        if (devicePolicySizeTrackingEnabled()) {
+        if (Flags.devicePolicySizeTrackingInternalEnabled()) {
             PolicySizeVerifier.enforceMaxParcelableFieldsLength(value);
         }
     }
diff --git a/core/java/android/app/admin/ComponentNamePolicyValue.java b/core/java/android/app/admin/ComponentNamePolicyValue.java
index 4d36195..a957dbf 100644
--- a/core/java/android/app/admin/ComponentNamePolicyValue.java
+++ b/core/java/android/app/admin/ComponentNamePolicyValue.java
@@ -16,10 +16,9 @@
 
 package android.app.admin;
 
-import static android.app.admin.flags.Flags.devicePolicySizeTrackingEnabled;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.admin.flags.Flags;
 import android.content.ComponentName;
 import android.os.Parcel;
 
@@ -32,7 +31,7 @@
 
     public ComponentNamePolicyValue(@NonNull ComponentName value) {
         super(value);
-        if (devicePolicySizeTrackingEnabled()) {
+        if (Flags.devicePolicySizeTrackingInternalEnabled()) {
             PolicySizeVerifier.enforceMaxComponentNameLength(value);
         }
     }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 083705b..b25ebf6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -14071,7 +14071,7 @@
     public void setAuditLogEnabled(boolean enabled) {
         throwIfParentInstance("setAuditLogEnabled");
         try {
-            mService.setAuditLogEnabled(mContext.getPackageName(), true);
+            mService.setAuditLogEnabled(mContext.getPackageName(), enabled);
         } catch (RemoteException re) {
             re.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/admin/IntentFilterPolicyKey.java b/core/java/android/app/admin/IntentFilterPolicyKey.java
index de7ff9f..63c3a4cb 100644
--- a/core/java/android/app/admin/IntentFilterPolicyKey.java
+++ b/core/java/android/app/admin/IntentFilterPolicyKey.java
@@ -19,12 +19,12 @@
 import static android.app.admin.PolicyUpdateReceiver.EXTRA_INTENT_FILTER;
 import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_BUNDLE_KEY;
 import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_KEY;
-import static android.app.admin.flags.Flags.devicePolicySizeTrackingEnabled;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.app.admin.flags.Flags;
 import android.content.IntentFilter;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -60,7 +60,7 @@
     @TestApi
     public IntentFilterPolicyKey(@NonNull String identifier, @NonNull IntentFilter filter) {
         super(identifier);
-        if (devicePolicySizeTrackingEnabled()) {
+        if (Flags.devicePolicySizeTrackingInternalEnabled()) {
             PolicySizeVerifier.enforceMaxParcelableFieldsLength(filter);
         }
         mFilter = Objects.requireNonNull(filter);
diff --git a/core/java/android/app/admin/LockTaskPolicy.java b/core/java/android/app/admin/LockTaskPolicy.java
index 9d6ce24..a36ea05 100644
--- a/core/java/android/app/admin/LockTaskPolicy.java
+++ b/core/java/android/app/admin/LockTaskPolicy.java
@@ -16,11 +16,10 @@
 
 package android.app.admin;
 
-import static android.app.admin.flags.Flags.devicePolicySizeTrackingEnabled;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.app.admin.flags.Flags;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -136,7 +135,7 @@
     }
 
     private void setPackagesInternal(Set<String> packages) {
-        if (devicePolicySizeTrackingEnabled()) {
+        if (Flags.devicePolicySizeTrackingInternalEnabled()) {
             for (String p : packages) {
                 PolicySizeVerifier.enforceMaxPackageNameLength(p);
             }
diff --git a/core/java/android/app/admin/PackagePermissionPolicyKey.java b/core/java/android/app/admin/PackagePermissionPolicyKey.java
index 2241fdd..389585f 100644
--- a/core/java/android/app/admin/PackagePermissionPolicyKey.java
+++ b/core/java/android/app/admin/PackagePermissionPolicyKey.java
@@ -20,12 +20,12 @@
 import static android.app.admin.PolicyUpdateReceiver.EXTRA_PERMISSION_NAME;
 import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_BUNDLE_KEY;
 import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_KEY;
-import static android.app.admin.flags.Flags.devicePolicySizeTrackingEnabled;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.app.admin.flags.Flags;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -59,7 +59,7 @@
     public PackagePermissionPolicyKey(@NonNull String identifier, @NonNull String packageName,
             @NonNull String permissionName) {
         super(identifier);
-        if (devicePolicySizeTrackingEnabled()) {
+        if (Flags.devicePolicySizeTrackingInternalEnabled()) {
             PolicySizeVerifier.enforceMaxPackageNameLength(packageName);
             PolicySizeVerifier.enforceMaxStringLength(permissionName, "permissionName");
         }
diff --git a/core/java/android/app/admin/PackagePolicyKey.java b/core/java/android/app/admin/PackagePolicyKey.java
index 2ea17a1..68dc797 100644
--- a/core/java/android/app/admin/PackagePolicyKey.java
+++ b/core/java/android/app/admin/PackagePolicyKey.java
@@ -19,12 +19,12 @@
 import static android.app.admin.PolicyUpdateReceiver.EXTRA_PACKAGE_NAME;
 import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_BUNDLE_KEY;
 import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_KEY;
-import static android.app.admin.flags.Flags.devicePolicySizeTrackingEnabled;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.app.admin.flags.Flags;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -55,7 +55,7 @@
     @TestApi
     public PackagePolicyKey(@NonNull String key, @NonNull String packageName) {
         super(key);
-        if (devicePolicySizeTrackingEnabled()) {
+        if (Flags.devicePolicySizeTrackingInternalEnabled()) {
             PolicySizeVerifier.enforceMaxPackageNameLength(packageName);
         }
         mPackageName = Objects.requireNonNull((packageName));
diff --git a/core/java/android/app/admin/PolicySizeVerifier.java b/core/java/android/app/admin/PolicySizeVerifier.java
index d5e8ea4..792ebc6 100644
--- a/core/java/android/app/admin/PolicySizeVerifier.java
+++ b/core/java/android/app/admin/PolicySizeVerifier.java
@@ -88,6 +88,10 @@
      * Throw if Parcelable contains any string that's too long to be serialized.
      */
     public static void enforceMaxParcelableFieldsLength(Parcelable parcelable) {
+        // TODO(b/326662716) rework to protect against infinite recursion.
+        if (true) {
+            return;
+        }
         Class<?> clazz = parcelable.getClass();
 
         Field[] fields = clazz.getDeclaredFields();
diff --git a/core/java/android/app/admin/StringPolicyValue.java b/core/java/android/app/admin/StringPolicyValue.java
index f4d4adc..8995c0f 100644
--- a/core/java/android/app/admin/StringPolicyValue.java
+++ b/core/java/android/app/admin/StringPolicyValue.java
@@ -16,10 +16,9 @@
 
 package android.app.admin;
 
-import static android.app.admin.flags.Flags.devicePolicySizeTrackingEnabled;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.admin.flags.Flags;
 import android.os.Parcel;
 
 import java.util.Objects;
@@ -31,7 +30,7 @@
 
     public StringPolicyValue(@NonNull String value) {
         super(value);
-        if (devicePolicySizeTrackingEnabled()) {
+        if (Flags.devicePolicySizeTrackingInternalEnabled()) {
             PolicySizeVerifier.enforceMaxStringLength(value, "policyValue");
         }
     }
diff --git a/core/java/android/app/admin/StringSetPolicyValue.java b/core/java/android/app/admin/StringSetPolicyValue.java
index 82fe761..f37dfee 100644
--- a/core/java/android/app/admin/StringSetPolicyValue.java
+++ b/core/java/android/app/admin/StringSetPolicyValue.java
@@ -16,10 +16,9 @@
 
 package android.app.admin;
 
-import static android.app.admin.flags.Flags.devicePolicySizeTrackingEnabled;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.admin.flags.Flags;
 import android.os.Parcel;
 
 import java.util.HashSet;
@@ -33,7 +32,7 @@
 
     public StringSetPolicyValue(@NonNull Set<String> value) {
         super(value);
-        if (devicePolicySizeTrackingEnabled()) {
+        if (Flags.devicePolicySizeTrackingInternalEnabled()) {
             for (String str : value) {
                 PolicySizeVerifier.enforceMaxStringLength(str, "policyValue");
             }
diff --git a/core/java/android/app/admin/UserRestrictionPolicyKey.java b/core/java/android/app/admin/UserRestrictionPolicyKey.java
index d69a5f0..ee90ccd 100644
--- a/core/java/android/app/admin/UserRestrictionPolicyKey.java
+++ b/core/java/android/app/admin/UserRestrictionPolicyKey.java
@@ -17,11 +17,11 @@
 package android.app.admin;
 
 import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_KEY;
-import static android.app.admin.flags.Flags.devicePolicySizeTrackingEnabled;
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.app.admin.flags.Flags;
 import android.os.Bundle;
 import android.os.Parcel;
 
@@ -45,7 +45,7 @@
     @TestApi
     public UserRestrictionPolicyKey(@NonNull String identifier, @NonNull String restriction) {
         super(identifier);
-        if (devicePolicySizeTrackingEnabled()) {
+        if (Flags.devicePolicySizeTrackingInternalEnabled()) {
             PolicySizeVerifier.enforceMaxStringLength(restriction, "restriction");
         }
         mRestriction = Objects.requireNonNull(restriction);
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index cbd8e5b..1927019 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -10,7 +10,14 @@
 flag {
   name: "device_policy_size_tracking_enabled"
   namespace: "enterprise"
-  description: "Add feature to track the total policy size and have a max threshold."
+  description: "Add feature to track the total policy size and have a max threshold - public API changes"
+  bug: "281543351"
+}
+
+flag {
+  name: "device_policy_size_tracking_internal_enabled"
+  namespace: "enterprise"
+  description: "Add feature to track the total policy size and have a max threshold - internal changes"
   bug: "281543351"
 }
 
@@ -117,6 +124,9 @@
     namespace: "enterprise"
     description: "Exempt the default sms app of the context user for suspension when calling setPersonalAppsSuspended"
     bug: "309183330"
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
 }
 
 flag {
@@ -146,3 +156,10 @@
   description: "Allow to query whether MTE is enabled or not to check for compliance for enterprise policy"
   bug: "322777918"
 }
+
+flag {
+  name: "esim_management_ux_enabled"
+  namespace: "enterprise"
+  description: "Enable UX changes for esim management"
+  bug: "295301164"
+}
diff --git a/core/java/android/app/ambient_context.aconfig b/core/java/android/app/ambient_context.aconfig
deleted file mode 100644
index 3f73da2..0000000
--- a/core/java/android/app/ambient_context.aconfig
+++ /dev/null
@@ -1,8 +0,0 @@
-package: "android.app"
-
-flag {
-  namespace: "biometrics_integration"
-  name: "ambient_heart_rate"
-  description: "Feature flag for adding heart rate api to ambient context."
-  bug: "318309481"
-}
diff --git a/core/java/android/app/ambientcontext/AmbientContextEvent.java b/core/java/android/app/ambientcontext/AmbientContextEvent.java
index 5ab7991..13d959c 100644
--- a/core/java/android/app/ambientcontext/AmbientContextEvent.java
+++ b/core/java/android/app/ambientcontext/AmbientContextEvent.java
@@ -16,9 +16,7 @@
 
 package android.app.ambientcontext;
 
-import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
-import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcelable;
@@ -70,14 +68,6 @@
     public static final int EVENT_BACK_DOUBLE_TAP = 3;
 
     /**
-     * The integer indicating a heart rate measurement was done.
-     *
-     * @see #getRatePerMinute
-     */
-    @Event @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE)
-    public static final int EVENT_HEART_RATE = 4;
-
-    /**
      * Integer indicating the start of wearable vendor defined events that can be detected.
      * These depend on the vendor implementation.
      */
@@ -89,19 +79,12 @@
      */
     public static final String KEY_VENDOR_WEARABLE_EVENT_NAME = "wearable_event_name";
 
-    /**
-     * Default value for {@link #getRatePerMinute}. Indicates that the rate of the event is unknown.
-     */
-    @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE)
-    public static final int RATE_PER_MINUTE_UNKNOWN = -1;
-
     /** @hide */
     @IntDef(prefix = { "EVENT_" }, value = {
             EVENT_UNKNOWN,
             EVENT_COUGH,
             EVENT_SNORE,
             EVENT_BACK_DOUBLE_TAP,
-            EVENT_HEART_RATE,
             EVENT_VENDOR_WEARABLE_START,
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -187,16 +170,6 @@
         return new PersistableBundle();
     }
 
-    /**
-     * Rate per minute of the event during the start to end time.
-     *
-     * @return the rate per minute, or {@link #RATE_PER_MINUTE_UNKNOWN} if the rate is unknown.
-     */
-    private final @IntRange(from = -1) int mRatePerMinute;
-    private static int defaultRatePerMinute() {
-        return RATE_PER_MINUTE_UNKNOWN;
-    }
-
 
 
     // Code below generated by codegen v1.0.23.
@@ -206,8 +179,6 @@
     //
     // To regenerate run:
     // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/app/ambientcontext/AmbientContextEvent.java
-    // then manually add @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE) back to flagged
-    // APIs.
     //
     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
     //   Settings > Editor > Code Style > Formatter Control
@@ -220,7 +191,6 @@
         EVENT_COUGH,
         EVENT_SNORE,
         EVENT_BACK_DOUBLE_TAP,
-        EVENT_HEART_RATE,
         EVENT_VENDOR_WEARABLE_START
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -239,8 +209,6 @@
                     return "EVENT_SNORE";
             case EVENT_BACK_DOUBLE_TAP:
                     return "EVENT_BACK_DOUBLE_TAP";
-            case EVENT_HEART_RATE:
-                    return "EVENT_HEART_RATE";
             case EVENT_VENDOR_WEARABLE_START:
                     return "EVENT_VENDOR_WEARABLE_START";
             default: return Integer.toHexString(value);
@@ -287,8 +255,7 @@
             @NonNull Instant endTime,
             @LevelValue int confidenceLevel,
             @LevelValue int densityLevel,
-            @NonNull PersistableBundle vendorData,
-            @IntRange(from = -1) int ratePerMinute) {
+            @NonNull PersistableBundle vendorData) {
         this.mEventType = eventType;
         com.android.internal.util.AnnotationValidations.validate(
                 EventCode.class, null, mEventType);
@@ -307,10 +274,6 @@
         this.mVendorData = vendorData;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mVendorData);
-        this.mRatePerMinute = ratePerMinute;
-        com.android.internal.util.AnnotationValidations.validate(
-                IntRange.class, null, mRatePerMinute,
-                "from", -1);
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -367,17 +330,6 @@
         return mVendorData;
     }
 
-    /**
-     * Rate per minute of the event during the start to end time.
-     *
-     * @return the rate per minute, or {@link #RATE_PER_MINUTE_UNKNOWN} if the rate is unknown.
-     */
-    @DataClass.Generated.Member
-    @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE)
-    public @IntRange(from = -1) int getRatePerMinute() {
-        return mRatePerMinute;
-    }
-
     @Override
     @DataClass.Generated.Member
     public String toString() {
@@ -390,8 +342,7 @@
                 "endTime = " + mEndTime + ", " +
                 "confidenceLevel = " + mConfidenceLevel + ", " +
                 "densityLevel = " + mDensityLevel + ", " +
-                "vendorData = " + mVendorData + ", " +
-                "ratePerMinute = " + mRatePerMinute +
+                "vendorData = " + mVendorData +
         " }";
     }
 
@@ -429,7 +380,6 @@
         dest.writeInt(mConfidenceLevel);
         dest.writeInt(mDensityLevel);
         dest.writeTypedObject(mVendorData, flags);
-        dest.writeInt(mRatePerMinute);
     }
 
     @Override
@@ -449,7 +399,6 @@
         int confidenceLevel = in.readInt();
         int densityLevel = in.readInt();
         PersistableBundle vendorData = (PersistableBundle) in.readTypedObject(PersistableBundle.CREATOR);
-        int ratePerMinute = in.readInt();
 
         this.mEventType = eventType;
         com.android.internal.util.AnnotationValidations.validate(
@@ -469,10 +418,6 @@
         this.mVendorData = vendorData;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mVendorData);
-        this.mRatePerMinute = ratePerMinute;
-        com.android.internal.util.AnnotationValidations.validate(
-                IntRange.class, null, mRatePerMinute,
-                "from", -1);
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -504,7 +449,6 @@
         private @LevelValue int mConfidenceLevel;
         private @LevelValue int mDensityLevel;
         private @NonNull PersistableBundle mVendorData;
-        private @IntRange(from = -1) int mRatePerMinute;
 
         private long mBuilderFieldsSet = 0L;
 
@@ -581,22 +525,10 @@
             return this;
         }
 
-        /**
-         * Rate per minute of the event during the start to end time.
-         */
-        @DataClass.Generated.Member
-        @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE)
-        public @NonNull Builder setRatePerMinute(@IntRange(from = -1) int value) {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x40;
-            mRatePerMinute = value;
-            return this;
-        }
-
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull AmbientContextEvent build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x80; // Mark builder used
+            mBuilderFieldsSet |= 0x40; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x1) == 0) {
                 mEventType = defaultEventType();
@@ -616,22 +548,18 @@
             if ((mBuilderFieldsSet & 0x20) == 0) {
                 mVendorData = defaultVendorData();
             }
-            if ((mBuilderFieldsSet & 0x40) == 0) {
-                mRatePerMinute = defaultRatePerMinute();
-            }
             AmbientContextEvent o = new AmbientContextEvent(
                     mEventType,
                     mStartTime,
                     mEndTime,
                     mConfidenceLevel,
                     mDensityLevel,
-                    mVendorData,
-                    mRatePerMinute);
+                    mVendorData);
             return o;
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x80) != 0) {
+            if ((mBuilderFieldsSet & 0x40) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -639,10 +567,10 @@
     }
 
     @DataClass.Generated(
-            time = 1705575046107L,
+            time = 1709014715064L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/app/ambientcontext/AmbientContextEvent.java",
-            inputSignatures = "public static final  int EVENT_UNKNOWN\npublic static final  int EVENT_COUGH\npublic static final  int EVENT_SNORE\npublic static final  int EVENT_BACK_DOUBLE_TAP\npublic static final @android.app.ambientcontext.AmbientContextEvent.Event @android.annotation.FlaggedApi int EVENT_HEART_RATE\npublic static final  int EVENT_VENDOR_WEARABLE_START\npublic static final  java.lang.String KEY_VENDOR_WEARABLE_EVENT_NAME\npublic static final @android.annotation.FlaggedApi int RATE_PER_MINUTE_UNKNOWN\npublic static final  int LEVEL_UNKNOWN\npublic static final  int LEVEL_LOW\npublic static final  int LEVEL_MEDIUM_LOW\npublic static final  int LEVEL_MEDIUM\npublic static final  int LEVEL_MEDIUM_HIGH\npublic static final  int LEVEL_HIGH\nprivate final @android.app.ambientcontext.AmbientContextEvent.EventCode int mEventType\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mStartTime\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mEndTime\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mConfidenceLevel\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mDensityLevel\nprivate final @android.annotation.NonNull android.os.PersistableBundle mVendorData\nprivate final @android.annotation.IntRange int mRatePerMinute\nprivate static  int defaultEventType()\nprivate static @android.annotation.NonNull java.time.Instant defaultStartTime()\nprivate static @android.annotation.NonNull java.time.Instant defaultEndTime()\nprivate static  int defaultConfidenceLevel()\nprivate static  int defaultDensityLevel()\nprivate static  android.os.PersistableBundle defaultVendorData()\nprivate static  int defaultRatePerMinute()\nclass AmbientContextEvent extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=false, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+            inputSignatures = "public static final  int EVENT_UNKNOWN\npublic static final  int EVENT_COUGH\npublic static final  int EVENT_SNORE\npublic static final  int EVENT_BACK_DOUBLE_TAP\npublic static final  int EVENT_VENDOR_WEARABLE_START\npublic static final  java.lang.String KEY_VENDOR_WEARABLE_EVENT_NAME\npublic static final  int LEVEL_UNKNOWN\npublic static final  int LEVEL_LOW\npublic static final  int LEVEL_MEDIUM_LOW\npublic static final  int LEVEL_MEDIUM\npublic static final  int LEVEL_MEDIUM_HIGH\npublic static final  int LEVEL_HIGH\nprivate final @android.app.ambientcontext.AmbientContextEvent.EventCode int mEventType\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mStartTime\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mEndTime\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mConfidenceLevel\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mDensityLevel\nprivate final @android.annotation.NonNull android.os.PersistableBundle mVendorData\nprivate static  int defaultEventType()\nprivate static @android.annotation.NonNull java.time.Instant defaultStartTime()\nprivate static @android.annotation.NonNull java.time.Instant defaultEndTime()\nprivate static  int defaultConfidenceLevel()\nprivate static  int defaultDensityLevel()\nprivate static  android.os.PersistableBundle defaultVendorData()\nclass AmbientContextEvent extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=false, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/app/backup/BackupManagerMonitor.java b/core/java/android/app/backup/BackupManagerMonitor.java
index 812bf8e..c66478f 100644
--- a/core/java/android/app/backup/BackupManagerMonitor.java
+++ b/core/java/android/app/backup/BackupManagerMonitor.java
@@ -145,6 +145,25 @@
    */
   public static final String EXTRA_LOG_OPERATION_TYPE = "android.app.backup.extra.OPERATION_TYPE";
 
+  /**
+   * List of system components that do not support restore in a  V-> U OS downgrade, even if
+   * restoreAnyVersion is set to true.
+   * Read from Settings.Secure.V_TO_U_RESTORE_DENYLIST
+   *
+   * @hide
+   */
+  public static final String EXTRA_LOG_V_TO_U_DENYLIST = "android.app.backup.extra.V_TO_U_DENYLIST";
+
+  /**
+   * List of system components that support restore in a  V-> U OS downgrade, even if
+   * restoreAnyVersion is set to false.
+   * Read from Settings.Secure.V_TO_U_RESTORE_ALLOWLIST
+   *
+   * @hide
+   */
+  public static final String EXTRA_LOG_V_TO_U_ALLOWLIST =
+          "android.app.backup.extra.V_TO_U_ALLOWLIST";
+
   // TODO complete this list with all log messages. And document properly.
   public static final int LOG_EVENT_ID_FULL_BACKUP_CANCEL = 4;
   public static final int LOG_EVENT_ID_ILLEGAL_KEY = 5;
@@ -241,6 +260,15 @@
   /** Agent error during {@link PerformUnifiedRestoreTask#restoreFinished()}
    @hide */
   public static final int LOG_EVENT_ID_AGENT_FAILURE = 69;
+  /** V to U restore attempt, pkg is eligible
+   @hide */
+  public static final int LOG_EVENT_ID_V_TO_U_RESTORE_PKG_ELIGIBLE = 70;
+  /** V to U restore attempt, pkg is not eligible
+   @hide */
+  public static final int LOG_EVENT_ID_V_TO_U_RESTORE_PKG_NOT_ELIGIBLE = 71;
+  /** V to U restore attempt, allowlist and denlist are set
+   @hide */
+  public static final int LOG_EVENT_ID_V_TO_U_RESTORE_SET_LIST = 72;
 
   /**
    * This method will be called each time something important happens on BackupManager.
diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
index bc8fac5..6317725 100644
--- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
+++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
@@ -29,6 +29,7 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Trace;
+import android.window.ActivityWindowInfo;
 
 import java.util.Objects;
 
@@ -39,6 +40,7 @@
 public class ActivityConfigurationChangeItem extends ActivityTransactionItem {
 
     private Configuration mConfiguration;
+    private ActivityWindowInfo mActivityWindowInfo;
 
     @Override
     public void preExecute(@NonNull ClientTransactionHandler client) {
@@ -49,11 +51,12 @@
     }
 
     @Override
-    public void execute(@NonNull ClientTransactionHandler client, @Nullable ActivityClientRecord r,
+    public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
             @NonNull PendingTransactionActions pendingActions) {
         // TODO(lifecycler): detect if PIP or multi-window mode changed and report it here.
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged");
-        client.handleActivityConfigurationChanged(r, mConfiguration, INVALID_DISPLAY);
+        client.handleActivityConfigurationChanged(r, mConfiguration, INVALID_DISPLAY,
+                mActivityWindowInfo);
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
 
@@ -70,7 +73,7 @@
     /** Obtain an instance initialized with provided params. */
     @NonNull
     public static ActivityConfigurationChangeItem obtain(@NonNull IBinder activityToken,
-            @NonNull Configuration config) {
+            @NonNull Configuration config, @NonNull ActivityWindowInfo activityWindowInfo) {
         ActivityConfigurationChangeItem instance =
                 ObjectPool.obtain(ActivityConfigurationChangeItem.class);
         if (instance == null) {
@@ -78,6 +81,7 @@
         }
         instance.setActivityToken(activityToken);
         instance.mConfiguration = new Configuration(config);
+        instance.mActivityWindowInfo = new ActivityWindowInfo(activityWindowInfo);
 
         return instance;
     }
@@ -86,6 +90,7 @@
     public void recycle() {
         super.recycle();
         mConfiguration = null;
+        mActivityWindowInfo = null;
         ObjectPool.recycle(this);
     }
 
@@ -97,12 +102,14 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         super.writeToParcel(dest, flags);
         dest.writeTypedObject(mConfiguration, flags);
+        dest.writeTypedObject(mActivityWindowInfo, flags);
     }
 
     /** Read from Parcel. */
     private ActivityConfigurationChangeItem(@NonNull Parcel in) {
         super(in);
         mConfiguration = in.readTypedObject(Configuration.CREATOR);
+        mActivityWindowInfo = in.readTypedObject(ActivityWindowInfo.CREATOR);
     }
 
     public static final @NonNull Creator<ActivityConfigurationChangeItem> CREATOR =
@@ -125,7 +132,8 @@
             return false;
         }
         final ActivityConfigurationChangeItem other = (ActivityConfigurationChangeItem) o;
-        return Objects.equals(mConfiguration, other.mConfiguration);
+        return Objects.equals(mConfiguration, other.mConfiguration)
+                && Objects.equals(mActivityWindowInfo, other.mActivityWindowInfo);
     }
 
     @Override
@@ -133,12 +141,14 @@
         int result = 17;
         result = 31 * result + super.hashCode();
         result = 31 * result + Objects.hashCode(mConfiguration);
+        result = 31 * result + Objects.hashCode(mActivityWindowInfo);
         return result;
     }
 
     @Override
     public String toString() {
         return "ActivityConfigurationChange{" + super.toString()
-                + ",config=" + mConfiguration + "}";
+                + ",config=" + mConfiguration
+                + ",activityWindowInfo=" + mActivityWindowInfo + "}";
     }
 }
diff --git a/core/java/android/app/servertransaction/ActivityRelaunchItem.java b/core/java/android/app/servertransaction/ActivityRelaunchItem.java
index cbb0ae7..6da871a 100644
--- a/core/java/android/app/servertransaction/ActivityRelaunchItem.java
+++ b/core/java/android/app/servertransaction/ActivityRelaunchItem.java
@@ -30,6 +30,7 @@
 import android.os.Trace;
 import android.util.MergedConfiguration;
 import android.util.Slog;
+import android.window.ActivityWindowInfo;
 
 import com.android.internal.content.ReferrerIntent;
 
@@ -50,6 +51,7 @@
     private int mConfigChanges;
     private MergedConfiguration mConfig;
     private boolean mPreserveWindow;
+    private ActivityWindowInfo mActivityWindowInfo;
 
     /**
      * A record that was properly configured for relaunch. Execution will be cancelled if not
@@ -64,7 +66,7 @@
             CompatibilityInfo.applyOverrideScaleIfNeeded(mConfig);
         }
         mActivityClientRecord = client.prepareRelaunchActivity(getActivityToken(), mPendingResults,
-                mPendingNewIntents, mConfigChanges, mConfig, mPreserveWindow);
+                mPendingNewIntents, mConfigChanges, mConfig, mPreserveWindow, mActivityWindowInfo);
     }
 
     @Override
@@ -101,7 +103,8 @@
     public static ActivityRelaunchItem obtain(@NonNull IBinder activityToken,
             @Nullable List<ResultInfo> pendingResults,
             @Nullable List<ReferrerIntent> pendingNewIntents, int configChanges,
-            @NonNull MergedConfiguration config, boolean preserveWindow) {
+            @NonNull MergedConfiguration config, boolean preserveWindow,
+            @NonNull ActivityWindowInfo activityWindowInfo) {
         ActivityRelaunchItem instance = ObjectPool.obtain(ActivityRelaunchItem.class);
         if (instance == null) {
             instance = new ActivityRelaunchItem();
@@ -113,6 +116,7 @@
         instance.mConfigChanges = configChanges;
         instance.mConfig = new MergedConfiguration(config);
         instance.mPreserveWindow = preserveWindow;
+        instance.mActivityWindowInfo = new ActivityWindowInfo(activityWindowInfo);
 
         return instance;
     }
@@ -126,6 +130,7 @@
         mConfig = null;
         mPreserveWindow = false;
         mActivityClientRecord = null;
+        mActivityWindowInfo = null;
         ObjectPool.recycle(this);
     }
 
@@ -141,6 +146,7 @@
         dest.writeInt(mConfigChanges);
         dest.writeTypedObject(mConfig, flags);
         dest.writeBoolean(mPreserveWindow);
+        dest.writeTypedObject(mActivityWindowInfo, flags);
     }
 
     /** Read from Parcel. */
@@ -151,6 +157,7 @@
         mConfigChanges = in.readInt();
         mConfig = in.readTypedObject(MergedConfiguration.CREATOR);
         mPreserveWindow = in.readBoolean();
+        mActivityWindowInfo = in.readTypedObject(ActivityWindowInfo.CREATOR);
     }
 
     public static final @NonNull Creator<ActivityRelaunchItem> CREATOR =
@@ -176,7 +183,8 @@
         return Objects.equals(mPendingResults, other.mPendingResults)
                 && Objects.equals(mPendingNewIntents, other.mPendingNewIntents)
                 && mConfigChanges == other.mConfigChanges && Objects.equals(mConfig, other.mConfig)
-                && mPreserveWindow == other.mPreserveWindow;
+                && mPreserveWindow == other.mPreserveWindow
+                && Objects.equals(mActivityWindowInfo, other.mActivityWindowInfo);
     }
 
     @Override
@@ -188,6 +196,7 @@
         result = 31 * result + mConfigChanges;
         result = 31 * result + Objects.hashCode(mConfig);
         result = 31 * result + (mPreserveWindow ? 1 : 0);
+        result = 31 * result + Objects.hashCode(mActivityWindowInfo);
         return result;
     }
 
@@ -198,6 +207,7 @@
                 + ",pendingNewIntents=" + mPendingNewIntents
                 + ",configChanges="  + mConfigChanges
                 + ",config=" + mConfig
-                + ",preserveWindow" + mPreserveWindow + "}";
+                + ",preserveWindow=" + mPreserveWindow
+                + ",activityWindowInfo=" + mActivityWindowInfo + "}";
     }
 }
diff --git a/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java
index 79696e0..48081bb 100644
--- a/core/java/android/app/servertransaction/ClientTransaction.java
+++ b/core/java/android/app/servertransaction/ClientTransaction.java
@@ -23,6 +23,7 @@
 import android.app.ClientTransactionHandler;
 import android.app.IApplicationThread;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -54,10 +55,12 @@
     @Nullable
     private List<ClientTransactionItem> mTransactionItems;
 
-    /** A list of individual callbacks to a client. */
-    // TODO(b/324203798): cleanup after remove UnsupportedAppUsage
-    @UnsupportedAppUsage
+    /** @deprecated use {@link #getTransactionItems} instead. */
     @Nullable
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
+            trackingBug = 324203798,
+            publicAlternatives = "Use {@code #getTransactionItems()}")
+    @Deprecated
     private List<ClientTransactionItem> mActivityCallbacks;
 
     /**
@@ -126,42 +129,42 @@
         setActivityTokenIfNotSet(activityCallback);
     }
 
-    /**
-     * Gets the list of callbacks.
-     * @deprecated use {@link #getTransactionItems()} instead.
-     */
-    // TODO(b/324203798): cleanup after remove UnsupportedAppUsage
-    @Nullable
+    /** @deprecated use {@link #getTransactionItems()} instead. */
     @VisibleForTesting
-    @UnsupportedAppUsage
+    @Nullable
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
+            trackingBug = 324203798,
+            publicAlternatives = "Use {@code #getTransactionItems()}")
     @Deprecated
     public List<ClientTransactionItem> getCallbacks() {
         return mActivityCallbacks;
     }
 
     /**
-     * @deprecated a transaction can contain {@link ClientTransactionItem} of different activities,
+     * A transaction can contain {@link ClientTransactionItem} of different activities,
      * this must not be used. For any unsupported app usages, please be aware that this is set to
      * the activity of the first item in {@link #getTransactionItems()}.
+     *
+     * @deprecated use {@link ClientTransactionItem#getActivityToken()} instead.
      */
-    // TODO(b/324203798): cleanup after remove UnsupportedAppUsage
     @VisibleForTesting
     @Nullable
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
+            trackingBug = 324203798,
+            publicAlternatives = "Use {@code android.app.servertransaction"
+                    + ".ClientTransactionItem#getActivityToken()}")
     @Deprecated
     public IBinder getActivityToken() {
         return mActivityToken;
     }
 
-    /**
-     * Gets the target state lifecycle request.
-     * @deprecated use {@link #getTransactionItems()} instead.
-     */
-    // TODO(b/324203798): cleanup after remove UnsupportedAppUsage
+    /** @deprecated use {@link #getTransactionItems()} instead. */
     @VisibleForTesting(visibility = PACKAGE)
-    @UnsupportedAppUsage
-    @Deprecated
     @Nullable
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
+            trackingBug = 324203798,
+            publicAlternatives = "Use {@code #getTransactionItems()}")
+    @Deprecated
     public ActivityLifecycleItem getLifecycleStateRequest() {
         return mLifecycleStateRequest;
     }
diff --git a/core/java/android/app/servertransaction/ClientTransactionListenerController.java b/core/java/android/app/servertransaction/ClientTransactionListenerController.java
index 1a8136e..7383d07 100644
--- a/core/java/android/app/servertransaction/ClientTransactionListenerController.java
+++ b/core/java/android/app/servertransaction/ClientTransactionListenerController.java
@@ -16,16 +16,24 @@
 
 package android.app.servertransaction;
 
+import static com.android.window.flags.Flags.activityWindowInfoFlag;
 import static com.android.window.flags.Flags.bundleClientTransactionFlag;
 
 import static java.util.Objects.requireNonNull;
 
 import android.annotation.NonNull;
+import android.app.Activity;
 import android.app.ActivityThread;
 import android.hardware.display.DisplayManagerGlobal;
+import android.os.IBinder;
+import android.util.ArraySet;
+import android.window.ActivityWindowInfo;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.util.function.BiConsumer;
+
 /**
  * Singleton controller to manage listeners to individual {@link ClientTransaction}.
  *
@@ -35,8 +43,14 @@
 
     private static ClientTransactionListenerController sController;
 
+    private final Object mLock = new Object();
     private final DisplayManagerGlobal mDisplayManager;
 
+    /** Listeners registered via {@link #registerActivityWindowInfoChangedListener(BiConsumer)}. */
+    @GuardedBy("mLock")
+    private final ArraySet<BiConsumer<IBinder, ActivityWindowInfo>>
+            mActivityWindowInfoChangedListeners = new ArraySet<>();
+
     /** Gets the singleton controller. */
     @NonNull
     public static ClientTransactionListenerController getInstance() {
@@ -62,6 +76,57 @@
     }
 
     /**
+     * Registers to listen on activity {@link ActivityWindowInfo} change.
+     * The listener will be invoked with two parameters: {@link Activity#getActivityToken()} and
+     * {@link ActivityWindowInfo}.
+     */
+    public void registerActivityWindowInfoChangedListener(
+            @NonNull BiConsumer<IBinder, ActivityWindowInfo> listener) {
+        if (!activityWindowInfoFlag()) {
+            return;
+        }
+        synchronized (mLock) {
+            mActivityWindowInfoChangedListeners.add(listener);
+        }
+    }
+
+    /**
+     * Unregisters the listener that was previously registered via
+     * {@link #registerActivityWindowInfoChangedListener(BiConsumer)}
+     */
+    public void unregisterActivityWindowInfoChangedListener(
+            @NonNull BiConsumer<IBinder, ActivityWindowInfo> listener) {
+        if (!activityWindowInfoFlag()) {
+            return;
+        }
+        synchronized (mLock) {
+            mActivityWindowInfoChangedListeners.remove(listener);
+        }
+    }
+
+    /**
+     * Called when receives a {@link ClientTransaction} that is updating an activity's
+     * {@link ActivityWindowInfo}.
+     */
+    public void onActivityWindowInfoChanged(@NonNull IBinder activityToken,
+            @NonNull ActivityWindowInfo activityWindowInfo) {
+        if (!activityWindowInfoFlag()) {
+            return;
+        }
+        final Object[] activityWindowInfoChangedListeners;
+        synchronized (mLock) {
+            if (mActivityWindowInfoChangedListeners.isEmpty()) {
+                return;
+            }
+            activityWindowInfoChangedListeners = mActivityWindowInfoChangedListeners.toArray();
+        }
+        for (Object activityWindowInfoChangedListener : activityWindowInfoChangedListeners) {
+            ((BiConsumer<IBinder, ActivityWindowInfo>) activityWindowInfoChangedListener)
+                    .accept(activityToken, activityWindowInfo);
+        }
+    }
+
+    /**
      * Called when receives a {@link ClientTransaction} that is updating display-related
      * window configuration.
      */
diff --git a/core/java/android/app/servertransaction/DestroyActivityItem.java b/core/java/android/app/servertransaction/DestroyActivityItem.java
index f9cf075..b0213d7 100644
--- a/core/java/android/app/servertransaction/DestroyActivityItem.java
+++ b/core/java/android/app/servertransaction/DestroyActivityItem.java
@@ -33,7 +33,6 @@
 public class DestroyActivityItem extends ActivityLifecycleItem {
 
     private boolean mFinished;
-    private int mConfigChanges;
 
     @Override
     public void preExecute(@NonNull ClientTransactionHandler client) {
@@ -44,7 +43,7 @@
     public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
             @NonNull PendingTransactionActions pendingActions) {
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy");
-        client.handleDestroyActivity(r, mFinished, mConfigChanges,
+        client.handleDestroyActivity(r, mFinished,
                 false /* getNonConfigInstance */, "DestroyActivityItem");
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
@@ -67,15 +66,13 @@
 
     /** Obtain an instance initialized with provided params. */
     @NonNull
-    public static DestroyActivityItem obtain(@NonNull IBinder activityToken, boolean finished,
-            int configChanges) {
+    public static DestroyActivityItem obtain(@NonNull IBinder activityToken, boolean finished) {
         DestroyActivityItem instance = ObjectPool.obtain(DestroyActivityItem.class);
         if (instance == null) {
             instance = new DestroyActivityItem();
         }
         instance.setActivityToken(activityToken);
         instance.mFinished = finished;
-        instance.mConfigChanges = configChanges;
 
         return instance;
     }
@@ -84,7 +81,6 @@
     public void recycle() {
         super.recycle();
         mFinished = false;
-        mConfigChanges = 0;
         ObjectPool.recycle(this);
     }
 
@@ -95,14 +91,12 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         super.writeToParcel(dest, flags);
         dest.writeBoolean(mFinished);
-        dest.writeInt(mConfigChanges);
     }
 
     /** Read from Parcel. */
     private DestroyActivityItem(@NonNull Parcel in) {
         super(in);
         mFinished = in.readBoolean();
-        mConfigChanges = in.readInt();
     }
 
     public static final @NonNull Creator<DestroyActivityItem> CREATOR = new Creator<>() {
@@ -124,7 +118,7 @@
             return false;
         }
         final DestroyActivityItem other = (DestroyActivityItem) o;
-        return mFinished == other.mFinished && mConfigChanges == other.mConfigChanges;
+        return mFinished == other.mFinished;
     }
 
     @Override
@@ -132,14 +126,12 @@
         int result = 17;
         result = 31 * result + super.hashCode();
         result = 31 * result + (mFinished ? 1 : 0);
-        result = 31 * result + mConfigChanges;
         return result;
     }
 
     @Override
     public String toString() {
         return "DestroyActivityItem{" + super.toString()
-                + ",finished=" + mFinished
-                + ",mConfigChanges=" + mConfigChanges + "}";
+                + ",finished=" + mFinished + "}";
     }
 }
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 95f5ad0..f02cb21 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -42,6 +42,7 @@
 import android.os.Parcel;
 import android.os.PersistableBundle;
 import android.os.Trace;
+import android.window.ActivityWindowInfo;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractor;
@@ -81,6 +82,8 @@
     private boolean mLaunchedFromBubble;
     private IBinder mTaskFragmentToken;
     private IBinder mInitialCallerInfoAccessToken;
+    private ActivityWindowInfo mActivityWindowInfo;
+
     /**
      * It is only non-null if the process is the first time to launch activity. It is only an
      * optimization for quick look up of the interface so the field is ignored for comparison.
@@ -107,7 +110,7 @@
                 mOverrideConfig, mReferrer, mVoiceInteractor, mState, mPersistentState,
                 mPendingResults, mPendingNewIntents, mSceneTransitionInfo, mIsForward,
                 mProfilerInfo, client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble,
-                mTaskFragmentToken, mInitialCallerInfoAccessToken);
+                mTaskFragmentToken, mInitialCallerInfoAccessToken, mActivityWindowInfo);
         client.handleLaunchActivity(r, pendingActions, mDeviceId, null /* customIntent */);
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
@@ -141,7 +144,8 @@
             boolean isForward, @Nullable ProfilerInfo profilerInfo, @NonNull IBinder assistToken,
             @Nullable IActivityClientController activityClientController,
             @NonNull IBinder shareableActivityToken, boolean launchedFromBubble,
-            @Nullable IBinder taskFragmentToken, @NonNull IBinder initialCallerInfoAccessToken) {
+            @Nullable IBinder taskFragmentToken, @NonNull IBinder initialCallerInfoAccessToken,
+            @NonNull ActivityWindowInfo activityWindowInfo) {
         LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class);
         if (instance == null) {
             instance = new LaunchActivityItem();
@@ -156,7 +160,8 @@
                 sceneTransitionInfo, isForward,
                 profilerInfo != null ? new ProfilerInfo(profilerInfo) : null,
                 assistToken, activityClientController, shareableActivityToken,
-                launchedFromBubble, taskFragmentToken, initialCallerInfoAccessToken);
+                launchedFromBubble, taskFragmentToken, initialCallerInfoAccessToken,
+                new ActivityWindowInfo(activityWindowInfo));
 
         return instance;
     }
@@ -171,7 +176,7 @@
     @Override
     public void recycle() {
         setValues(this, null, null, 0, null, null, null, 0, null, null, 0, null, null, null, null,
-                null, false, null, null, null, null, false, null, null);
+                null, false, null, null, null, null, false, null, null, null);
         ObjectPool.recycle(this);
     }
 
@@ -203,6 +208,7 @@
         dest.writeBoolean(mLaunchedFromBubble);
         dest.writeStrongBinder(mTaskFragmentToken);
         dest.writeStrongBinder(mInitialCallerInfoAccessToken);
+        dest.writeTypedObject(mActivityWindowInfo, flags);
     }
 
     /** Read from Parcel. */
@@ -223,7 +229,8 @@
                 in.readStrongBinder(),
                 in.readBoolean(),
                 in.readStrongBinder(),
-                in.readStrongBinder());
+                in.readStrongBinder(),
+                in.readTypedObject(ActivityWindowInfo.CREATOR));
     }
 
     public static final @NonNull Creator<LaunchActivityItem> CREATOR = new Creator<>() {
@@ -264,7 +271,8 @@
                 && Objects.equals(mShareableActivityToken, other.mShareableActivityToken)
                 && Objects.equals(mTaskFragmentToken, other.mTaskFragmentToken)
                 && Objects.equals(mInitialCallerInfoAccessToken,
-                        other.mInitialCallerInfoAccessToken);
+                        other.mInitialCallerInfoAccessToken)
+                && Objects.equals(mActivityWindowInfo, other.mActivityWindowInfo);
     }
 
     @Override
@@ -289,6 +297,7 @@
         result = 31 * result + Objects.hashCode(mShareableActivityToken);
         result = 31 * result + Objects.hashCode(mTaskFragmentToken);
         result = 31 * result + Objects.hashCode(mInitialCallerInfoAccessToken);
+        result = 31 * result + Objects.hashCode(mActivityWindowInfo);
         return result;
     }
 
@@ -335,7 +344,9 @@
                 + ",sceneTransitionInfo=" + mSceneTransitionInfo
                 + ",profilerInfo=" + mProfilerInfo
                 + ",assistToken=" + mAssistToken
-                + ",shareableActivityToken=" + mShareableActivityToken + "}";
+                + ",shareableActivityToken=" + mShareableActivityToken
+                + ",activityWindowInfo=" + mActivityWindowInfo
+                + "}";
     }
 
     // Using the same method to set and clear values to make sure we don't forget anything
@@ -351,7 +362,8 @@
             @Nullable ProfilerInfo profilerInfo, @Nullable IBinder assistToken,
             @Nullable IActivityClientController activityClientController,
             @Nullable IBinder shareableActivityToken, boolean launchedFromBubble,
-            @Nullable IBinder taskFragmentToken, @Nullable IBinder initialCallerInfoAccessToken) {
+            @Nullable IBinder taskFragmentToken, @Nullable IBinder initialCallerInfoAccessToken,
+            @Nullable ActivityWindowInfo activityWindowInfo) {
         instance.mActivityToken = activityToken;
         instance.mIntent = intent;
         instance.mIdent = ident;
@@ -375,5 +387,6 @@
         instance.mLaunchedFromBubble = launchedFromBubble;
         instance.mTaskFragmentToken = taskFragmentToken;
         instance.mInitialCallerInfoAccessToken = initialCallerInfoAccessToken;
+        instance.mActivityWindowInfo = activityWindowInfo;
     }
 }
diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java
index 1353d16..0702c45 100644
--- a/core/java/android/app/servertransaction/MoveToDisplayItem.java
+++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java
@@ -28,6 +28,7 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Trace;
+import android.window.ActivityWindowInfo;
 
 import java.util.Objects;
 
@@ -39,6 +40,7 @@
 
     private int mTargetDisplayId;
     private Configuration mConfiguration;
+    private ActivityWindowInfo mActivityWindowInfo;
 
     @Override
     public void preExecute(@NonNull ClientTransactionHandler client) {
@@ -52,7 +54,8 @@
     public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
             @NonNull PendingTransactionActions pendingActions) {
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityMovedToDisplay");
-        client.handleActivityConfigurationChanged(r, mConfiguration, mTargetDisplayId);
+        client.handleActivityConfigurationChanged(r, mConfiguration, mTargetDisplayId,
+                mActivityWindowInfo);
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
 
@@ -69,7 +72,7 @@
     /** Obtain an instance initialized with provided params. */
     @NonNull
     public static MoveToDisplayItem obtain(@NonNull IBinder activityToken, int targetDisplayId,
-            @NonNull Configuration configuration) {
+            @NonNull Configuration configuration, @NonNull ActivityWindowInfo activityWindowInfo) {
         MoveToDisplayItem instance = ObjectPool.obtain(MoveToDisplayItem.class);
         if (instance == null) {
             instance = new MoveToDisplayItem();
@@ -77,6 +80,7 @@
         instance.setActivityToken(activityToken);
         instance.mTargetDisplayId = targetDisplayId;
         instance.mConfiguration = new Configuration(configuration);
+        instance.mActivityWindowInfo = new ActivityWindowInfo(activityWindowInfo);
 
         return instance;
     }
@@ -86,6 +90,7 @@
         super.recycle();
         mTargetDisplayId = 0;
         mConfiguration = null;
+        mActivityWindowInfo = null;
         ObjectPool.recycle(this);
     }
 
@@ -97,6 +102,7 @@
         super.writeToParcel(dest, flags);
         dest.writeInt(mTargetDisplayId);
         dest.writeTypedObject(mConfiguration, flags);
+        dest.writeTypedObject(mActivityWindowInfo, flags);
     }
 
     /** Read from Parcel. */
@@ -104,6 +110,7 @@
         super(in);
         mTargetDisplayId = in.readInt();
         mConfiguration = in.readTypedObject(Configuration.CREATOR);
+        mActivityWindowInfo = in.readTypedObject(ActivityWindowInfo.CREATOR);
     }
 
     public static final @NonNull Creator<MoveToDisplayItem> CREATOR = new Creator<>() {
@@ -126,7 +133,8 @@
         }
         final MoveToDisplayItem other = (MoveToDisplayItem) o;
         return mTargetDisplayId == other.mTargetDisplayId
-                && Objects.equals(mConfiguration, other.mConfiguration);
+                && Objects.equals(mConfiguration, other.mConfiguration)
+                && Objects.equals(mActivityWindowInfo, other.mActivityWindowInfo);
     }
 
     @Override
@@ -135,6 +143,7 @@
         result = 31 * result + super.hashCode();
         result = 31 * result + mTargetDisplayId;
         result = 31 * result + mConfiguration.hashCode();
+        result = 31 * result + Objects.hashCode(mActivityWindowInfo);
         return result;
     }
 
@@ -142,6 +151,7 @@
     public String toString() {
         return "MoveToDisplayItem{" + super.toString()
                 + ",targetDisplayId=" + mTargetDisplayId
-                + ",configuration=" + mConfiguration + "}";
+                + ",configuration=" + mConfiguration
+                + ",activityWindowInfo=" + mActivityWindowInfo + "}";
     }
 }
diff --git a/core/java/android/app/servertransaction/PauseActivityItem.java b/core/java/android/app/servertransaction/PauseActivityItem.java
index 8f1e90b..d230284 100644
--- a/core/java/android/app/servertransaction/PauseActivityItem.java
+++ b/core/java/android/app/servertransaction/PauseActivityItem.java
@@ -37,7 +37,6 @@
 
     private boolean mFinished;
     private boolean mUserLeaving;
-    private int mConfigChanges;
     private boolean mDontReport;
     private boolean mAutoEnteringPip;
 
@@ -45,7 +44,7 @@
     public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
             @NonNull PendingTransactionActions pendingActions) {
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
-        client.handlePauseActivity(r, mFinished, mUserLeaving, mConfigChanges, mAutoEnteringPip,
+        client.handlePauseActivity(r, mFinished, mUserLeaving, mAutoEnteringPip,
                 pendingActions, "PAUSE_ACTIVITY_ITEM");
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
@@ -72,7 +71,7 @@
     /** Obtain an instance initialized with provided params. */
     @NonNull
     public static PauseActivityItem obtain(@NonNull IBinder activityToken, boolean finished,
-            boolean userLeaving, int configChanges, boolean dontReport, boolean autoEnteringPip) {
+            boolean userLeaving, boolean dontReport, boolean autoEnteringPip) {
         PauseActivityItem instance = ObjectPool.obtain(PauseActivityItem.class);
         if (instance == null) {
             instance = new PauseActivityItem();
@@ -80,7 +79,6 @@
         instance.setActivityToken(activityToken);
         instance.mFinished = finished;
         instance.mUserLeaving = userLeaving;
-        instance.mConfigChanges = configChanges;
         instance.mDontReport = dontReport;
         instance.mAutoEnteringPip = autoEnteringPip;
 
@@ -91,7 +89,7 @@
     @NonNull
     public static PauseActivityItem obtain(@NonNull IBinder activityToken) {
         return obtain(activityToken, false /* finished */, false /* userLeaving */,
-                0 /* configChanges */, true /* dontReport */, false /* autoEnteringPip*/);
+                true /* dontReport */, false /* autoEnteringPip*/);
     }
 
     @Override
@@ -99,7 +97,6 @@
         super.recycle();
         mFinished = false;
         mUserLeaving = false;
-        mConfigChanges = 0;
         mDontReport = false;
         mAutoEnteringPip = false;
         ObjectPool.recycle(this);
@@ -113,7 +110,6 @@
         super.writeToParcel(dest, flags);
         dest.writeBoolean(mFinished);
         dest.writeBoolean(mUserLeaving);
-        dest.writeInt(mConfigChanges);
         dest.writeBoolean(mDontReport);
         dest.writeBoolean(mAutoEnteringPip);
     }
@@ -123,7 +119,6 @@
         super(in);
         mFinished = in.readBoolean();
         mUserLeaving = in.readBoolean();
-        mConfigChanges = in.readInt();
         mDontReport = in.readBoolean();
         mAutoEnteringPip = in.readBoolean();
     }
@@ -148,7 +143,7 @@
         }
         final PauseActivityItem other = (PauseActivityItem) o;
         return mFinished == other.mFinished && mUserLeaving == other.mUserLeaving
-                && mConfigChanges == other.mConfigChanges && mDontReport == other.mDontReport
+                && mDontReport == other.mDontReport
                 && mAutoEnteringPip == other.mAutoEnteringPip;
     }
 
@@ -158,7 +153,6 @@
         result = 31 * result + super.hashCode();
         result = 31 * result + (mFinished ? 1 : 0);
         result = 31 * result + (mUserLeaving ? 1 : 0);
-        result = 31 * result + mConfigChanges;
         result = 31 * result + (mDontReport ? 1 : 0);
         result = 31 * result + (mAutoEnteringPip ? 1 : 0);
         return result;
@@ -169,7 +163,6 @@
         return "PauseActivityItem{" + super.toString()
                 + ",finished=" + mFinished
                 + ",userLeaving=" + mUserLeaving
-                + ",configChanges=" + mConfigChanges
                 + ",dontReport=" + mDontReport
                 + ",autoEnteringPip=" + mAutoEnteringPip + "}";
     }
diff --git a/core/java/android/app/servertransaction/StopActivityItem.java b/core/java/android/app/servertransaction/StopActivityItem.java
index b8ce52d..def7b3f 100644
--- a/core/java/android/app/servertransaction/StopActivityItem.java
+++ b/core/java/android/app/servertransaction/StopActivityItem.java
@@ -19,7 +19,6 @@
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.ActivityThread.ActivityClientRecord;
 import android.app.ClientTransactionHandler;
 import android.os.IBinder;
@@ -34,13 +33,11 @@
 
     private static final String TAG = "StopActivityItem";
 
-    private int mConfigChanges;
-
     @Override
     public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
             @NonNull PendingTransactionActions pendingActions) {
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
-        client.handleStopActivity(r, mConfigChanges, pendingActions,
+        client.handleStopActivity(r, pendingActions,
                 true /* finalStateRequest */, "STOP_ACTIVITY_ITEM");
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
@@ -63,16 +60,14 @@
     /**
      * Obtain an instance initialized with provided params.
      * @param activityToken the activity that stops.
-     * @param configChanges Configuration pieces that changed.
      */
     @NonNull
-    public static StopActivityItem obtain(@NonNull IBinder activityToken, int configChanges) {
+    public static StopActivityItem obtain(@NonNull IBinder activityToken) {
         StopActivityItem instance = ObjectPool.obtain(StopActivityItem.class);
         if (instance == null) {
             instance = new StopActivityItem();
         }
         instance.setActivityToken(activityToken);
-        instance.mConfigChanges = configChanges;
 
         return instance;
     }
@@ -80,23 +75,14 @@
     @Override
     public void recycle() {
         super.recycle();
-        mConfigChanges = 0;
         ObjectPool.recycle(this);
     }
 
     // Parcelable implementation
 
-    /** Write to Parcel. */
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        super.writeToParcel(dest, flags);
-        dest.writeInt(mConfigChanges);
-    }
-
     /** Read from Parcel. */
     private StopActivityItem(@NonNull Parcel in) {
         super(in);
-        mConfigChanges = in.readInt();
     }
 
     public static final @NonNull Creator<StopActivityItem> CREATOR = new Creator<>() {
@@ -110,28 +96,7 @@
     };
 
     @Override
-    public boolean equals(@Nullable Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (!super.equals(o)) {
-            return false;
-        }
-        final StopActivityItem other = (StopActivityItem) o;
-        return mConfigChanges == other.mConfigChanges;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = 17;
-        result = 31 * result + super.hashCode();
-        result = 31 * result + mConfigChanges;
-        return result;
-    }
-
-    @Override
     public String toString() {
-        return "StopActivityItem{" + super.toString()
-                + ",configChanges=" + mConfigChanges + "}";
+        return "StopActivityItem{" + super.toString() + "}";
     }
 }
diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java
index fa73c99..c837191 100644
--- a/core/java/android/app/servertransaction/TransactionExecutor.java
+++ b/core/java/android/app/servertransaction/TransactionExecutor.java
@@ -334,18 +334,18 @@
                     break;
                 case ON_PAUSE:
                     mTransactionHandler.handlePauseActivity(r, false /* finished */,
-                            false /* userLeaving */, 0 /* configChanges */,
+                            false /* userLeaving */,
                             false /* autoEnteringPip */, mPendingActions,
                             "LIFECYCLER_PAUSE_ACTIVITY");
                     break;
                 case ON_STOP:
-                    mTransactionHandler.handleStopActivity(r, 0 /* configChanges */,
+                    mTransactionHandler.handleStopActivity(r,
                             mPendingActions, false /* finalStateRequest */,
                             "LIFECYCLER_STOP_ACTIVITY");
                     break;
                 case ON_DESTROY:
                     mTransactionHandler.handleDestroyActivity(r, false /* finishing */,
-                            0 /* configChanges */, false /* getNonConfigInstance */,
+                            false /* getNonConfigInstance */,
                             "performLifecycleSequence. cycling to:" + path.get(size - 1));
                     break;
                 case ON_RESTART:
diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
index 475c6fb..710261a 100644
--- a/core/java/android/app/servertransaction/TransactionExecutorHelper.java
+++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
@@ -200,7 +200,7 @@
                 lifecycleItem = PauseActivityItem.obtain(r.token);
                 break;
             case ON_STOP:
-                lifecycleItem = StopActivityItem.obtain(r.token, 0 /* configChanges */);
+                lifecycleItem = StopActivityItem.obtain(r.token);
                 break;
             default:
                 lifecycleItem = ResumeActivityItem.obtain(r.token, false /* isForward */,
diff --git a/core/java/android/companion/virtual/VirtualDeviceInternal.java b/core/java/android/companion/virtual/VirtualDeviceInternal.java
index 39f6de7..00d5343 100644
--- a/core/java/android/companion/virtual/VirtualDeviceInternal.java
+++ b/core/java/android/companion/virtual/VirtualDeviceInternal.java
@@ -16,6 +16,9 @@
 
 package android.companion.virtual;
 
+import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
+
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -352,12 +355,20 @@
             @Nullable Executor executor,
             @Nullable VirtualAudioDevice.AudioConfigurationChangeCallback callback) {
         if (mVirtualAudioDevice == null) {
-            Context context = mContext;
-            if (Flags.deviceAwareRecordAudioPermission()) {
-                context = mContext.createDeviceContext(getDeviceId());
+            try {
+                Context context = mContext;
+                if (Flags.deviceAwareRecordAudioPermission()) {
+                    // When using a default policy for audio device-aware RECORD_AUDIO permission
+                    // should not take effect, thus register policies with the default context.
+                    if (mVirtualDevice.getDevicePolicy(POLICY_TYPE_AUDIO) == DEVICE_POLICY_CUSTOM) {
+                        context = mContext.createDeviceContext(getDeviceId());
+                    }
+                }
+                mVirtualAudioDevice = new VirtualAudioDevice(context, mVirtualDevice, display,
+                        executor, callback, () -> mVirtualAudioDevice = null);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
-            mVirtualAudioDevice = new VirtualAudioDevice(context, mVirtualDevice, display,
-                    executor, callback, () -> mVirtualAudioDevice = null);
         }
         return mVirtualAudioDevice;
     }
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 728c350..b421339 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -169,6 +169,8 @@
  */
 @android.ravenwood.annotation.RavenwoodKeepWholeClass
 public class ClipData implements Parcelable {
+    private static final String TAG = "ClipData";
+
     static final String[] MIMETYPES_TEXT_PLAIN = new String[] {
         ClipDescription.MIMETYPE_TEXT_PLAIN };
     static final String[] MIMETYPES_TEXT_HTML = new String[] {
@@ -476,7 +478,6 @@
          * @return Returns the item's textual representation.
          */
 //BEGIN_INCLUDE(coerceToText)
-        @android.ravenwood.annotation.RavenwoodThrow
         public CharSequence coerceToText(Context context) {
             // If this Item has an explicit textual value, simply return that.
             CharSequence text = getText();
@@ -484,13 +485,20 @@
                 return text;
             }
 
+            // Gracefully handle cases where resolver isn't available
+            ContentResolver resolver = null;
+            try {
+                resolver = context.getContentResolver();
+            } catch (Exception e) {
+                Log.w(TAG, "Failed to obtain ContentResolver: " + e);
+            }
+
             // If this Item has a URI value, try using that.
             Uri uri = getUri();
-            if (uri != null) {
+            if (uri != null && resolver != null) {
                 // First see if the URI can be opened as a plain text stream
                 // (of any sub-type).  If so, this is the best textual
                 // representation for it.
-                final ContentResolver resolver = context.getContentResolver();
                 AssetFileDescriptor descr = null;
                 FileInputStream stream = null;
                 InputStreamReader reader = null;
@@ -499,7 +507,7 @@
                         // Ask for a stream of the desired type.
                         descr = resolver.openTypedAssetFileDescriptor(uri, "text/*", null);
                     } catch (SecurityException e) {
-                        Log.w("ClipData", "Failure opening stream", e);
+                        Log.w(TAG, "Failure opening stream", e);
                     } catch (FileNotFoundException|RuntimeException e) {
                         // Unable to open content URI as text...  not really an
                         // error, just something to ignore.
@@ -519,7 +527,7 @@
                             return builder.toString();
                         } catch (IOException e) {
                             // Something bad has happened.
-                            Log.w("ClipData", "Failure loading text", e);
+                            Log.w(TAG, "Failure loading text", e);
                             return e.toString();
                         }
                     }
@@ -528,7 +536,8 @@
                     IoUtils.closeQuietly(stream);
                     IoUtils.closeQuietly(reader);
                 }
-
+            }
+            if (uri != null) {
                 // If we couldn't open the URI as a stream, use the URI itself as a textual
                 // representation (but not for "content", "android.resource" or "file" schemes).
                 final String scheme = uri.getScheme();
@@ -704,7 +713,7 @@
                         }
 
                     } catch (SecurityException e) {
-                        Log.w("ClipData", "Failure opening stream", e);
+                        Log.w(TAG, "Failure opening stream", e);
 
                     } catch (FileNotFoundException e) {
                         // Unable to open content URI as text...  not really an
@@ -712,7 +721,7 @@
 
                     } catch (IOException e) {
                         // Something bad has happened.
-                        Log.w("ClipData", "Failure loading text", e);
+                        Log.w(TAG, "Failure loading text", e);
                         return Html.escapeHtml(e.toString());
 
                     } finally {
@@ -1123,7 +1132,7 @@
      *
      * @hide
      */
-    @android.ravenwood.annotation.RavenwoodThrow
+    @android.ravenwood.annotation.RavenwoodKeep
     public void prepareToLeaveProcess(boolean leavingPackage) {
         // Assume that callers are going to be granting permissions
         prepareToLeaveProcess(leavingPackage, Intent.FLAG_GRANT_READ_URI_PERMISSION);
@@ -1134,7 +1143,7 @@
      *
      * @hide
      */
-    @android.ravenwood.annotation.RavenwoodThrow
+    @android.ravenwood.annotation.RavenwoodReplace
     public void prepareToLeaveProcess(boolean leavingPackage, int intentFlags) {
         final int size = mItems.size();
         for (int i = 0; i < size; i++) {
@@ -1154,6 +1163,11 @@
         }
     }
 
+    /** @hide */
+    public void prepareToLeaveProcess$ravenwood(boolean leavingPackage, int intentFlags) {
+        // No process boundaries on Ravenwood; ignored
+    }
+
     /** {@hide} */
     @android.ravenwood.annotation.RavenwoodThrow
     public void prepareToEnterProcess(AttributionSource source) {
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index 107f107..2fabcba 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -50,6 +50,7 @@
  * </div>
  */
 @SystemService(Context.CLIPBOARD_SERVICE)
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
 public class ClipboardManager extends android.text.ClipboardManager {
 
     /**
@@ -143,6 +144,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.MANAGE_CLIPBOARD_ACCESS_NOTIFICATION)
+    @android.ravenwood.annotation.RavenwoodThrow
     public boolean areClipboardAccessNotificationsEnabled() {
         try {
             return mService.areClipboardAccessNotificationsEnabledForUser(mContext.getUserId());
@@ -159,6 +161,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.MANAGE_CLIPBOARD_ACCESS_NOTIFICATION)
+    @android.ravenwood.annotation.RavenwoodThrow
     public void setClipboardAccessNotificationsEnabled(boolean enable) {
         try {
             mService.setClipboardAccessNotificationsEnabledForUser(enable, mContext.getUserId());
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index f77ebc1..70d2c7a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -83,6 +83,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
+import android.provider.E2eeContactKeysManager;
 import android.provider.MediaStore;
 import android.telephony.TelephonyRegistryManager;
 import android.util.AttributeSet;
@@ -4815,9 +4816,7 @@
      * @see android.net.thread.ThreadNetworkManager
      * @hide
      */
-    // TODO (b/325886480): update the flag to
-    // "com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM"
-    @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform")
+    @FlaggedApi(com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM)
     @SystemApi
     public static final String THREAD_NETWORK_SERVICE = "thread_network";
 
@@ -6566,10 +6565,10 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
-     * {@link android.provider.ContactKeysManager} to managing contact keys.
+     * {@link E2eeContactKeysManager} to managing contact keys.
      *
      * @see #getSystemService(String)
-     * @see android.provider.ContactKeysManager
+     * @see E2eeContactKeysManager
      */
     @FlaggedApi(android.provider.Flags.FLAG_USER_KEYS)
     public static final String CONTACT_KEYS_SERVICE = "contact_keys";
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index fd2af99..42dd87a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1064,7 +1064,11 @@
         }
 
         if (sender != null) {
-            intent.putExtra(EXTRA_CHOOSER_RESULT_INTENT_SENDER, sender);
+            if (android.service.chooser.Flags.enableChooserResult()) {
+                intent.putExtra(EXTRA_CHOOSER_RESULT_INTENT_SENDER, sender);
+            } else {
+                intent.putExtra(EXTRA_CHOSEN_COMPONENT_INTENT_SENDER, sender);
+            }
         }
 
         // Migrate any clip data and flags from target.
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index cec49c7..533fa51 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -67,6 +67,7 @@
     List<String> getPreInstalledSystemPackages(in UserHandle user);
     IntentSender getAppMarketActivityIntent(String callingPackage, String packageName,
             in UserHandle user);
+    IntentSender getPrivateSpaceSettingsIntent();
     void showAppDetailsAsUser(in IApplicationThread caller, String callingPackage,
             String callingFeatureId, in ComponentName component, in Rect sourceBounds,
             in Bundle opts, in UserHandle user);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index e437925..6bb9c33 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -899,6 +899,28 @@
     }
 
     /**
+     * Returns {@link IntentSender} which can be used to start the Private Space Settings Activity.
+     *
+     * <p> Caller should have {@link android.app.role.RoleManager.ROLE_HOME} and either of the
+     * permissions required.</p>
+     *
+     * @return {@link IntentSender} object which launches the Private Space Settings Activity, if
+     * successful, null otherwise.
+     * @hide
+     */
+    @Nullable
+    @FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE)
+    @RequiresPermission(conditional = true,
+            anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
+    public IntentSender getPrivateSpaceSettingsIntent() {
+        try {
+            return mService.getPrivateSpaceSettingsIntent();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it
      * returns null.
      *
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7a015cd..9f2f74b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3974,9 +3974,7 @@
      * The device is capable of communicating with other devices via
      * <a href="https://www.threadgroup.org">Thread</a> networking protocol.
      */
-    // TODO (b/325886480): update the flag to
-    // "com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM"
-    @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform")
+    @FlaggedApi(com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM)
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network";
 
@@ -4204,15 +4202,6 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
-     * {@link #hasSystemFeature}: The device supports multiple concurrent IME sessions.
-     */
-    @FlaggedApi("android.view.inputmethod.concurrent_input_methods")
-    @SdkConstant(SdkConstantType.FEATURE)
-    public static final String FEATURE_CONCURRENT_INPUT_METHODS =
-            "android.software.concurrent_input_methods";
-
-    /**
-     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports device policy enforcement via device admins.
      */
     @SdkConstant(SdkConstantType.FEATURE)
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 9c6aab4..5b0cee7 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -163,25 +163,12 @@
      * Because of this, developers must make sure to stop the foreground service even if
      * {@link android.app.Service#onTimeout(int, int)} is not called on such versions.
      *
-     * <p>Apps targeting API level {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} and
-     * later should <b>NOT</b> use this type: calling
-     * {@link android.app.Service#startForeground(int, android.app.Notification, int)} with
-     * this type on devices running {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} is
-     * still allowed, but it may throw an {@link android.app.InvalidForegroundServiceTypeException}
-     * in future platform releases.
-     *
-     * <p class="note">
-     * Use the {@link android.app.job.JobInfo.Builder#setUserInitiated(boolean)} API for
-     * user-initiated, network data transfers.
-     *
-     * @deprecated Use {@link android.app.job.JobInfo.Builder} APIs or alternate FGS types
-     * (like {@link #FOREGROUND_SERVICE_TYPE_MEDIA_PROCESSING}) applicable to your use-case.
+     * @see android.app.Service#onTimeout(int, int)
      */
     @RequiresPermission(
             value = Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC,
             conditional = true
     )
-    @Deprecated
     public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1 << 0;
 
     /**
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 3e9f260..8a3a3ad 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -112,6 +112,12 @@
     /**
      * Indicates that this user is disabled.
      *
+     * <p> This is currently used to indicate that a Managed Profile, when created via
+     * DevicePolicyManager, has not yet been provisioned; once the DPC provisions it, a DPM call
+     * will manually set it to enabled.
+     *
+     * <p>Users that are slated for deletion are also generally set to disabled.
+     *
      * <p>Note: If an ephemeral user is disabled, it shouldn't be later re-enabled. Ephemeral users
      * are disabled as their removal is in progress to indicate that they shouldn't be re-entered.
      */
@@ -398,6 +404,7 @@
         return UserManager.isUserTypePrivateProfile(userType);
     }
 
+    /** See {@link #FLAG_DISABLED}*/
     @UnsupportedAppUsage
     public boolean isEnabled() {
         return (flags & FLAG_DISABLED) != FLAG_DISABLED;
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 5e9d8f0..610057b 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -208,6 +208,14 @@
 }
 
 flag {
+    name: "restrict_nonpreloads_system_shareduids"
+    namespace: "package_manager_service"
+    description: "Feature flag to restrict apps from joining system shared uids"
+    bug: "308573169"
+    is_fixed_read_only: true
+}
+
+flag {
     name: "min_target_sdk_24"
     namespace: "responsible_apis"
     description: "Feature flag to bump min target sdk to 24"
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 22e233a..ac80561 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -177,3 +177,10 @@
     description: "Enable the sensitive notifications toggle to be visible in the Private space settings page"
     bug: "317067050"
 }
+
+flag {
+    name: "enable_private_space_intent_redirection"
+    namespace: "profile_experiences"
+    description: "Enable Private Space telephony and SMS intent redirection to the main user"
+    bug: "325576602"
+}
diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java
index 2e63664..3a9a0f91 100644
--- a/core/java/android/credentials/CredentialManager.java
+++ b/core/java/android/credentials/CredentialManager.java
@@ -23,6 +23,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
@@ -31,6 +32,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.IntentSender;
+import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.CancellationSignal;
@@ -57,6 +59,7 @@
  * to authenticate to the app.
  */
 @SystemService(Context.CREDENTIAL_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_CREDENTIALS)
 public final class CredentialManager {
     private static final String TAG = "CredentialManager";
     private static final Bundle OPTIONS_SENDER_BAL_OPTIN = ActivityOptions.makeBasic()
diff --git a/core/java/android/credentials/GetCandidateCredentialsResponse.java b/core/java/android/credentials/GetCandidateCredentialsResponse.java
index 6e53fd9..3d8ccaa 100644
--- a/core/java/android/credentials/GetCandidateCredentialsResponse.java
+++ b/core/java/android/credentials/GetCandidateCredentialsResponse.java
@@ -18,7 +18,7 @@
 
 import android.annotation.Hide;
 import android.annotation.NonNull;
-import android.app.PendingIntent;
+import android.content.Intent;
 import android.credentials.selection.GetCredentialProviderData;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -39,32 +39,22 @@
     @NonNull
     private final List<GetCredentialProviderData> mCandidateProviderDataList;
 
-    private final PendingIntent mPendingIntent;
+    @NonNull
+    private final Intent mIntent;
 
     /**
      * @hide
      */
     @Hide
     public GetCandidateCredentialsResponse(
-            GetCredentialResponse getCredentialResponse
-    ) {
-        mCandidateProviderDataList = null;
-        mPendingIntent = null;
-    }
-
-    /**
-     * @hide
-     */
-    @Hide
-    public GetCandidateCredentialsResponse(
-            List<GetCredentialProviderData> candidateProviderDataList,
-            PendingIntent pendingIntent
+            @NonNull List<GetCredentialProviderData> candidateProviderDataList,
+            @NonNull Intent intent
     ) {
         Preconditions.checkCollectionNotEmpty(
                 candidateProviderDataList,
                 /*valueName=*/ "candidateProviderDataList");
         mCandidateProviderDataList = new ArrayList<>(candidateProviderDataList);
-        mPendingIntent = pendingIntent;
+        mIntent = intent;
     }
 
     /**
@@ -81,8 +71,9 @@
      *
      * @hide
      */
-    public PendingIntent getPendingIntent() {
-        return mPendingIntent;
+    @NonNull
+    public Intent getIntent() {
+        return mIntent;
     }
 
     protected GetCandidateCredentialsResponse(Parcel in) {
@@ -91,14 +82,13 @@
         mCandidateProviderDataList = candidateProviderDataList;
 
         AnnotationValidations.validate(NonNull.class, null, mCandidateProviderDataList);
-
-        mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
+        mIntent = in.readTypedObject(Intent.CREATOR);
     }
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeTypedList(mCandidateProviderDataList);
-        dest.writeTypedObject(mPendingIntent, flags);
+        dest.writeTypedObject(mIntent, flags);
     }
 
     @Override
diff --git a/core/java/android/credentials/selection/IntentFactory.java b/core/java/android/credentials/selection/IntentFactory.java
index 4b0fa6d..79fba9b 100644
--- a/core/java/android/credentials/selection/IntentFactory.java
+++ b/core/java/android/credentials/selection/IntentFactory.java
@@ -80,17 +80,7 @@
             ArrayList<DisabledProviderData> disabledProviderDataList,
             @NonNull ResultReceiver resultReceiver) {
         Intent intent = new Intent();
-        ComponentName componentName =
-                ComponentName.unflattenFromString(
-                        Resources.getSystem()
-                                .getString(
-                                        com.android.internal.R.string
-                                                .config_credentialManagerDialogComponent));
-        ComponentName oemOverrideComponentName = getOemOverrideComponentName(context);
-        if (oemOverrideComponentName != null) {
-            componentName = oemOverrideComponentName;
-        }
-        intent.setComponent(componentName);
+        setCredentialSelectorUiComponentName(context, intent);
         intent.putParcelableArrayListExtra(
                 ProviderData.EXTRA_DISABLED_PROVIDER_DATA_LIST, disabledProviderDataList);
         intent.putExtra(RequestInfo.EXTRA_REQUEST_INFO, requestInfo);
@@ -100,6 +90,24 @@
         return intent;
     }
 
+    private static void setCredentialSelectorUiComponentName(@NonNull Context context,
+            @NonNull Intent intent) {
+        if (configurableSelectorUiEnabled()) {
+            ComponentName componentName = getOemOverrideComponentName(context);
+            if (componentName == null) {
+                componentName = ComponentName.unflattenFromString(Resources.getSystem().getString(
+                        com.android.internal.R.string
+                                .config_fallbackCredentialManagerDialogComponent));
+            }
+            intent.setComponent(componentName);
+        } else {
+            ComponentName componentName = ComponentName.unflattenFromString(Resources.getSystem()
+                    .getString(com.android.internal.R.string
+                            .config_fallbackCredentialManagerDialogComponent));
+            intent.setComponent(componentName);
+        }
+    }
+
     /**
      * Returns null if there is not an enabled and valid oem override component. It means the
      * default platform UI component name should be used instead.
@@ -107,44 +115,39 @@
     @Nullable
     private static ComponentName getOemOverrideComponentName(@NonNull Context context) {
         ComponentName result = null;
-        if (configurableSelectorUiEnabled()) {
-            if (Resources.getSystem().getBoolean(
-                    com.android.internal.R.bool.config_enableOemCredentialManagerDialogComponent)) {
-                String oemComponentString =
-                        Resources.getSystem()
-                                .getString(
-                                        com.android.internal.R.string
-                                                .config_oemCredentialManagerDialogComponent);
-                if (!TextUtils.isEmpty(oemComponentString)) {
-                    ComponentName oemComponentName = ComponentName.unflattenFromString(
-                            oemComponentString);
-                    if (oemComponentName != null) {
-                        try {
-                            ActivityInfo info = context.getPackageManager().getActivityInfo(
-                                    oemComponentName,
-                                    PackageManager.ComponentInfoFlags.of(
-                                            PackageManager.MATCH_SYSTEM_ONLY));
-                            if (info.enabled && info.exported) {
-                                Slog.i(TAG,
-                                        "Found enabled oem CredMan UI component."
-                                                + oemComponentString);
-                                result = oemComponentName;
-                            } else {
-                                Slog.i(TAG,
-                                        "Found enabled oem CredMan UI component but it was not "
-                                                + "enabled.");
-                            }
-                        } catch (PackageManager.NameNotFoundException e) {
-                            Slog.i(TAG, "Unable to find oem CredMan UI component: "
-                                    + oemComponentString + ".");
-                        }
+        String oemComponentString =
+                Resources.getSystem()
+                        .getString(
+                                com.android.internal.R.string
+                                        .config_oemCredentialManagerDialogComponent);
+        if (!TextUtils.isEmpty(oemComponentString)) {
+            ComponentName oemComponentName = ComponentName.unflattenFromString(
+                    oemComponentString);
+            if (oemComponentName != null) {
+                try {
+                    ActivityInfo info = context.getPackageManager().getActivityInfo(
+                            oemComponentName,
+                            PackageManager.ComponentInfoFlags.of(
+                                    PackageManager.MATCH_SYSTEM_ONLY));
+                    if (info.enabled && info.exported) {
+                        Slog.i(TAG,
+                                "Found enabled oem CredMan UI component."
+                                        + oemComponentString);
+                        result = oemComponentName;
                     } else {
-                        Slog.i(TAG, "Invalid OEM ComponentName format.");
+                        Slog.i(TAG,
+                                "Found enabled oem CredMan UI component but it was not "
+                                        + "enabled.");
                     }
-                } else {
-                    Slog.i(TAG, "Invalid empty OEM component name.");
+                } catch (PackageManager.NameNotFoundException e) {
+                    Slog.i(TAG, "Unable to find oem CredMan UI component: "
+                            + oemComponentString + ".");
                 }
+            } else {
+                Slog.i(TAG, "Invalid OEM ComponentName format.");
             }
+        } else {
+            Slog.i(TAG, "Invalid empty OEM component name.");
         }
         return result;
     }
@@ -186,16 +189,11 @@
      * Creates an Intent that cancels any UI matching the given request token id.
      */
     @NonNull
-    public static Intent createCancelUiIntent(@NonNull IBinder requestToken,
-            boolean shouldShowCancellationUi, @NonNull String appPackageName) {
+    public static Intent createCancelUiIntent(@NonNull Context context,
+            @NonNull IBinder requestToken, boolean shouldShowCancellationUi,
+            @NonNull String appPackageName) {
         Intent intent = new Intent();
-        ComponentName componentName =
-                ComponentName.unflattenFromString(
-                        Resources.getSystem()
-                                .getString(
-                                        com.android.internal.R.string
-                                                .config_credentialManagerDialogComponent));
-        intent.setComponent(componentName);
+        setCredentialSelectorUiComponentName(context, intent);
         intent.putExtra(CancelSelectionRequest.EXTRA_CANCEL_UI_REQUEST,
                 new CancelSelectionRequest(new RequestToken(requestToken), shouldShowCancellationUi,
                         appPackageName));
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index ecffe9e..faa2c70 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -392,8 +392,6 @@
             return;
         }
 
-        Log.i(TAG, walFile.getAbsolutePath() + " " + size + " bytes: Bigger than "
-                + threshold + "; truncating");
         try {
             executeForString("PRAGMA wal_checkpoint(TRUNCATE)", null, null);
             mConfiguration.shouldTruncateWalFile = false;
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 5dfeac7..d683d72 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -40,15 +40,12 @@
 import android.os.OperationCanceledException;
 import android.os.SystemProperties;
 import android.text.TextUtils;
-import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Printer;
 
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
 import dalvik.annotation.optimization.NeverCompile;
@@ -106,14 +103,8 @@
     // Stores reference to all databases opened in the current process.
     // (The referent Object is not used at this time.)
     // INVARIANT: Guarded by sActiveDatabases.
-    @GuardedBy("sActiveDatabases")
     private static WeakHashMap<SQLiteDatabase, Object> sActiveDatabases = new WeakHashMap<>();
 
-    // Tracks which database files are currently open.  If a database file is opened more than
-    // once at any given moment, the associated databases are marked as "concurrent".
-    @GuardedBy("sActiveDatabases")
-    private static final OpenTracker sOpenTracker = new OpenTracker();
-
     // Thread-local for database sessions that belong to this database.
     // Each thread has its own database session.
     // INVARIANT: Immutable.
@@ -519,7 +510,6 @@
 
     private void dispose(boolean finalized) {
         final SQLiteConnectionPool pool;
-        final String path;
         synchronized (mLock) {
             if (mCloseGuardLocked != null) {
                 if (finalized) {
@@ -530,12 +520,10 @@
 
             pool = mConnectionPoolLocked;
             mConnectionPoolLocked = null;
-            path = isInMemoryDatabase() ? null : getPath();
         }
 
         if (!finalized) {
             synchronized (sActiveDatabases) {
-                sOpenTracker.close(path);
                 sActiveDatabases.remove(this);
             }
 
@@ -1144,74 +1132,6 @@
         }
     }
 
-    /**
-     * Track the number of times a database file has been opened.  There is a primary connection
-     * associated with every open database, and these can contend with each other, leading to
-     * unexpected SQLiteDatabaseLockedException exceptions.  The tracking here is only advisory:
-     * multiply-opened databases are logged but no other action is taken.
-     *
-     * This class is not thread-safe.
-     */
-    private static class OpenTracker {
-        // The list of currently-open databases.  This maps the database file to the number of
-        // currently-active opens.
-        private final ArrayMap<String, Integer> mOpens = new ArrayMap<>();
-
-        // The maximum number of concurrently open database paths that will be stored.  Once this
-        // many paths have been recorded, further paths are logged but not saved.
-        private static final int MAX_RECORDED_PATHS = 20;
-
-        // The list of databases that were ever concurrently opened.
-        private final ArraySet<String> mConcurrent = new ArraySet<>();
-
-        /** Return the canonical path.  On error, just return the input path. */
-        private static String normalize(String path) {
-            try {
-                return new File(path).toPath().toRealPath().toString();
-            } catch (Exception e) {
-                // If there is an IO or security exception, just continue, using the input path.
-                return path;
-            }
-        }
-
-        /** Return true if the path is currently open in another SQLiteDatabase instance. */
-        void open(@Nullable String path) {
-            if (path == null) return;
-            path = normalize(path);
-
-            Integer count = mOpens.get(path);
-            if (count == null || count == 0) {
-                mOpens.put(path, 1);
-                return;
-            } else {
-                mOpens.put(path, count + 1);
-                if (mConcurrent.size() < MAX_RECORDED_PATHS) {
-                    mConcurrent.add(path);
-                }
-                Log.w(TAG, "multiple primary connections on " + path);
-                return;
-            }
-        }
-
-        void close(@Nullable String path) {
-            if (path == null) return;
-            path = normalize(path);
-            Integer count = mOpens.get(path);
-            if (count == null || count <= 0) {
-                Log.e(TAG, "open database counting failure on " + path);
-            } else if (count == 1) {
-                // Implicitly set the count to zero, and make mOpens smaller.
-                mOpens.remove(path);
-            } else {
-                mOpens.put(path, count - 1);
-            }
-        }
-
-        ArraySet<String> getConcurrentDatabasePaths() {
-            return new ArraySet<>(mConcurrent);
-        }
-    }
-
     private void open() {
         try {
             try {
@@ -1233,17 +1153,14 @@
     }
 
     private void openInner() {
-        final String path;
         synchronized (mLock) {
             assert mConnectionPoolLocked == null;
             mConnectionPoolLocked = SQLiteConnectionPool.open(mConfigurationLocked);
             mCloseGuardLocked.open("close");
-            path = isInMemoryDatabase() ? null : getPath();
         }
 
         synchronized (sActiveDatabases) {
             sActiveDatabases.put(this, null);
-            sOpenTracker.open(path);
         }
     }
 
@@ -2428,17 +2345,6 @@
     }
 
     /**
-     * Return list of databases that have been concurrently opened.
-     * @hide
-     */
-    @VisibleForTesting
-    public static ArraySet<String> getConcurrentDatabasePaths() {
-        synchronized (sActiveDatabases) {
-            return sOpenTracker.getConcurrentDatabasePaths();
-        }
-    }
-
-    /**
      * Returns true if the new version code is greater than the current database version.
      *
      * @param newVersion The new version code.
@@ -2860,19 +2766,6 @@
                 dumpDatabaseDirectory(printer, new File(dir), isSystem);
             }
         }
-
-        // Dump concurrently-opened database files, if any
-        final ArraySet<String> concurrent;
-        synchronized (sActiveDatabases) {
-            concurrent = sOpenTracker.getConcurrentDatabasePaths();
-        }
-        if (concurrent.size() > 0) {
-            printer.println("");
-            printer.println("Concurrently opened database files");
-            for (String f : concurrent) {
-                printer.println("  " + f);
-            }
-        }
     }
 
     private static void dumpDatabaseDirectory(Printer pw, File dir, boolean isSystem) {
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index 5e523c0..78c8954 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -377,8 +377,7 @@
                     if (writable) {
                         throw ex;
                     }
-                    Log.e(TAG, "Couldn't open " + mName
-                            + " for writing (will try read-only):", ex);
+                    Log.e(TAG, "Couldn't open database for writing (will try read-only):", ex);
                     params = params.toBuilder().addOpenFlags(SQLiteDatabase.OPEN_READONLY).build();
                     db = SQLiteDatabase.openDatabase(filePath, params);
                 }
@@ -425,11 +424,6 @@
             }
 
             onOpen(db);
-
-            if (db.isReadOnly()) {
-                Log.w(TAG, "Opened " + mName + " in read-only mode");
-            }
-
             mDatabase = db;
             return db;
         } finally {
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 57b437f..dc8f4b4 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -3521,7 +3521,7 @@
      * <p>When the key is present, only a PRIVATE/YUV output of the specified size is guaranteed
      * to be supported by the camera HAL in the secure camera mode. Any other format or
      * resolutions might not be supported. Use
-     * {@link CameraManager#isSessionConfigurationWithParametersSupported }
+     * {@link CameraDevice#isSessionConfigurationSupported }
      * API to query if a secure session configuration is supported if the device supports this
      * API.</p>
      * <p>If this key returns null on a device with SECURE_IMAGE_DATA capability, the application
@@ -5046,18 +5046,18 @@
 
     /**
      * <p>The version of the session configuration query
-     * {@link android.hardware.camera2.CameraManager#isSessionConfigurationWithParametersSupported }
+     * {@link android.hardware.camera2.CameraDevice.CameraDeviceSetup#isSessionConfigurationSupported }
      * API</p>
      * <p>The possible values in this key correspond to the values defined in
      * android.os.Build.VERSION_CODES. Each version defines a set of feature combinations the
      * camera device must reliably report whether they are supported via
-     * {@link android.hardware.camera2.CameraManager#isSessionConfigurationWithParametersSupported }
+     * {@link android.hardware.camera2.CameraDevice.CameraDeviceSetup#isSessionConfigurationSupported }
      * API. And the version is always less or equal to android.os.Build.VERSION.SDK_INT.</p>
      * <p>If set to UPSIDE_DOWN_CAKE, this camera device doesn't support
-     * {@link android.hardware.camera2.CameraManager#isSessionConfigurationWithParametersSupported }.
+     * {@link android.hardware.camera2.CameraDevice.CameraDeviceSetup#isSessionConfigurationSupported }.
      * Calling the method for this camera ID throws an UnsupportedOperationException.</p>
      * <p>If set to VANILLA_ICE_CREAM, the application can call
-     * {@link android.hardware.camera2.CameraManager#isSessionConfigurationWithParametersSupported }
+     * {@link android.hardware.camera2.CameraDevice.CameraDeviceSetup#isSessionConfigurationSupported }
      * to check if the combinations of below features are supported.</p>
      * <ul>
      * <li>A subset of LIMITED-level device stream combinations.</li>
@@ -6082,11 +6082,11 @@
 
     /**
      * <p>Minimum and maximum padding zoom factors supported by this camera device for
-     * {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } used for the
+     * android.efv.paddingZoomFactor used for the
      * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
      * extension.</p>
      * <p>The minimum and maximum padding zoom factors supported by the device for
-     * {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } used as part of the
+     * android.efv.paddingZoomFactor used as part of the
      * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
      * extension feature. This extension specific camera characteristic can be queried using
      * {@link android.hardware.camera2.CameraExtensionCharacteristics#get }.</p>
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 04e3dab..d2e4a61 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -753,25 +753,22 @@
     @FlaggedApi(Flags.FLAG_CAMERA_DEVICE_SETUP)
     public CameraDevice.CameraDeviceSetup getCameraDeviceSetup(@NonNull String cameraId)
             throws CameraAccessException {
-        if (cameraId == null) {
-            throw new IllegalArgumentException("cameraId was null");
-        }
-
-        if (CameraManagerGlobal.sCameraServiceDisabled) {
-            throw new CameraAccessException(CameraAccessException.CAMERA_DISABLED,
-                    "No cameras available on device");
-        }
-
-        if (!Arrays.asList(CameraManagerGlobal.get().getCameraIdList()).contains(cameraId)) {
-            throw new IllegalArgumentException(
-                    "Camera ID '" + cameraId + "' not available on device.");
-        }
-
+        // isCameraDeviceSetup does all the error checking we need.
         if (!isCameraDeviceSetupSupported(cameraId)) {
             throw new UnsupportedOperationException(
                     "CameraDeviceSetup is not supported for Camera ID: " + cameraId);
         }
 
+        return getCameraDeviceSetupUnsafe(cameraId);
+
+    }
+
+    /**
+     * Creates and returns a {@link CameraDeviceSetup} instance without any error checking. To
+     * be used (carefully) by callers who are sure that CameraDeviceSetup instance can be legally
+     * created and don't want to pay the latency cost of calling {@link #getCameraDeviceSetup}.
+     */
+    private CameraDevice.CameraDeviceSetup getCameraDeviceSetupUnsafe(@NonNull String cameraId) {
         return new CameraDeviceSetupImpl(cameraId, /*cameraManager=*/ this, mContext);
     }
 
@@ -809,12 +806,8 @@
             throw new IllegalArgumentException("Camera ID was null");
         }
 
-        if (CameraManagerGlobal.sCameraServiceDisabled) {
-            throw new CameraAccessException(CameraAccessException.CAMERA_DISABLED,
-                    "No cameras available on device");
-        }
-
-        if (!Arrays.asList(CameraManagerGlobal.get().getCameraIdList()).contains(cameraId)) {
+        if (CameraManagerGlobal.sCameraServiceDisabled
+                || !Arrays.asList(CameraManagerGlobal.get().getCameraIdList()).contains(cameraId)) {
             throw new IllegalArgumentException(
                     "Camera ID '" + cameraId + "' not available on device.");
         }
@@ -857,8 +850,9 @@
 
             ICameraDeviceUser cameraUser = null;
             CameraDevice.CameraDeviceSetup cameraDeviceSetup = null;
-            if (Flags.cameraDeviceSetup() && isCameraDeviceSetupSupported(cameraId)) {
-                cameraDeviceSetup = getCameraDeviceSetup(cameraId);
+            if (Flags.cameraDeviceSetup()
+                    && CameraDeviceSetupImpl.isCameraDeviceSetupSupported(characteristics)) {
+                cameraDeviceSetup = getCameraDeviceSetupUnsafe(cameraId);
             }
 
             android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index e24c98e..9fb561b 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -911,10 +911,10 @@
      * </ul>
      * <p>Combinations of logical and physical streams, or physical streams from different
      * physical cameras are not guaranteed. However, if the camera device supports
-     * {@link CameraManager#isSessionConfigurationWithParametersSupported },
+     * {@link CameraDevice#isSessionConfigurationSupported },
      * application must be able to query whether a stream combination involving physical
      * streams is supported by calling
-     * {@link CameraManager#isSessionConfigurationWithParametersSupported }.</p>
+     * {@link CameraDevice#isSessionConfigurationSupported }.</p>
      * <p>Camera application shouldn't assume that there are at most 1 rear camera and 1 front
      * camera in the system. For an application that switches between front and back cameras,
      * the recommendation is to switch between the first rear camera and the first front
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index 9fbe348..f3b7b91 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -260,7 +260,7 @@
          * smaller sizes, then the resulting
          * {@link android.hardware.camera2.params.SessionConfiguration session configuration} can
          * be tested either by calling {@link CameraDevice#createCaptureSession} or
-         * {@link CameraManager#isSessionConfigurationWithParametersSupported}.
+         * {@link CameraDeviceSetup#isSessionConfigurationSupported}.
          *
          * @return non-modifiable ascending list of available sizes.
          */
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 95526a8..8aacd5e 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -1379,7 +1379,6 @@
                     mSurfaceType != other.mSurfaceType ||
                     mIsDeferredConfig != other.mIsDeferredConfig ||
                     mIsShared != other.mIsShared ||
-                    mConfiguredFormat != other.mConfiguredFormat ||
                     mConfiguredDataspace != other.mConfiguredDataspace ||
                     mConfiguredGenerationId != other.mConfiguredGenerationId ||
                     !Objects.equals(mPhysicalCameraId, other.mPhysicalCameraId) ||
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 1f54959..2816f77 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -27,6 +27,7 @@
 import android.hardware.input.IKeyboardBacklightState;
 import android.hardware.input.IStickyModifierStateListener;
 import android.hardware.input.ITabletModeChangedListener;
+import android.hardware.input.KeyboardLayoutSelectionResult;
 import android.hardware.input.TouchCalibration;
 import android.os.CombinedVibration;
 import android.hardware.input.IInputSensorEventListener;
@@ -120,8 +121,9 @@
             String keyboardLayoutDescriptor);
 
     // New Keyboard layout config APIs
-    String getKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier, int userId,
-            in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype);
+    KeyboardLayoutSelectionResult getKeyboardLayoutForInputDevice(
+            in InputDeviceIdentifier identifier, int userId, in InputMethodInfo imeInfo,
+            in InputMethodSubtype imeSubtype);
 
     @EnforcePermission("SET_KEYBOARD_LAYOUT")
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 744dfae9..a1242fb 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -784,10 +784,10 @@
      *
      * @hide
      */
-    @Nullable
-    public String getKeyboardLayoutForInputDevice(@NonNull InputDeviceIdentifier identifier,
-            @UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
-            @Nullable InputMethodSubtype imeSubtype) {
+    @NonNull
+    public KeyboardLayoutSelectionResult getKeyboardLayoutForInputDevice(
+            @NonNull InputDeviceIdentifier identifier, @UserIdInt int userId,
+            @NonNull InputMethodInfo imeInfo, @Nullable InputMethodSubtype imeSubtype) {
         try {
             return mIm.getKeyboardLayoutForInputDevice(identifier, userId, imeInfo, imeSubtype);
         } catch (RemoteException ex) {
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/GoneSceneModule.kt b/core/java/android/hardware/input/KeyboardLayoutSelectionResult.aidl
similarity index 79%
rename from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/GoneSceneModule.kt
rename to core/java/android/hardware/input/KeyboardLayoutSelectionResult.aidl
index 5cc3b75d..13be2ff 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/GoneSceneModule.kt
+++ b/core/java/android/hardware/input/KeyboardLayoutSelectionResult.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.systemui.scene
+package android.hardware.input;
 
-import dagger.Module
-
-@Module interface GoneSceneModule
+parcelable KeyboardLayoutSelectionResult;
diff --git a/core/java/android/hardware/input/KeyboardLayoutSelectionResult.java b/core/java/android/hardware/input/KeyboardLayoutSelectionResult.java
new file mode 100644
index 0000000..5a1c947
--- /dev/null
+++ b/core/java/android/hardware/input/KeyboardLayoutSelectionResult.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.input;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcelable;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.internal.util.DataClass;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Provides information about the selected layout and the selection criteria when the caller calls
+ * {@link InputManager#getKeyboardLayoutForInputDevice(InputDeviceIdentifier, int, InputMethodInfo,
+ * InputMethodSubtype)}
+ *
+ * @hide
+ */
+
+@DataClass(genParcelable = true, genToString = true, genEqualsHashCode = true)
+public final class KeyboardLayoutSelectionResult implements Parcelable {
+    @Nullable
+    private final String mLayoutDescriptor;
+
+    /** Unspecified layout selection criteria */
+    public static final int LAYOUT_SELECTION_CRITERIA_UNSPECIFIED = 0;
+
+    /** Manual selection by user */
+    public static final int LAYOUT_SELECTION_CRITERIA_USER = 1;
+
+    /** Auto-detection based on device provided language tag and layout type */
+    public static final int LAYOUT_SELECTION_CRITERIA_DEVICE = 2;
+
+    /** Auto-detection based on IME provided language tag and layout type */
+    public static final int LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD = 3;
+
+    /** Default selection */
+    public static final int LAYOUT_SELECTION_CRITERIA_DEFAULT = 4;
+
+    /** Failed layout selection */
+    public static final KeyboardLayoutSelectionResult FAILED = new KeyboardLayoutSelectionResult(
+            null, LAYOUT_SELECTION_CRITERIA_UNSPECIFIED);
+
+    @LayoutSelectionCriteria
+    private final int mSelectionCriteria;
+
+
+
+    // 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/hardware/input/KeyboardLayoutSelectionResult.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @IntDef(prefix = "LAYOUT_SELECTION_CRITERIA_", value = {
+        LAYOUT_SELECTION_CRITERIA_UNSPECIFIED,
+        LAYOUT_SELECTION_CRITERIA_USER,
+        LAYOUT_SELECTION_CRITERIA_DEVICE,
+        LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD,
+        LAYOUT_SELECTION_CRITERIA_DEFAULT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface LayoutSelectionCriteria {}
+
+    @DataClass.Generated.Member
+    public static String layoutSelectionCriteriaToString(@LayoutSelectionCriteria int value) {
+        switch (value) {
+            case LAYOUT_SELECTION_CRITERIA_UNSPECIFIED:
+                    return "LAYOUT_SELECTION_CRITERIA_UNSPECIFIED";
+            case LAYOUT_SELECTION_CRITERIA_USER:
+                    return "LAYOUT_SELECTION_CRITERIA_USER";
+            case LAYOUT_SELECTION_CRITERIA_DEVICE:
+                    return "LAYOUT_SELECTION_CRITERIA_DEVICE";
+            case LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD:
+                    return "LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD";
+            case LAYOUT_SELECTION_CRITERIA_DEFAULT:
+                    return "LAYOUT_SELECTION_CRITERIA_DEFAULT";
+            default: return Integer.toHexString(value);
+        }
+    }
+
+    @DataClass.Generated.Member
+    public KeyboardLayoutSelectionResult(
+            @Nullable String layoutDescriptor,
+            @LayoutSelectionCriteria int selectionCriteria) {
+        this.mLayoutDescriptor = layoutDescriptor;
+        this.mSelectionCriteria = selectionCriteria;
+
+        if (!(mSelectionCriteria == LAYOUT_SELECTION_CRITERIA_UNSPECIFIED)
+                && !(mSelectionCriteria == LAYOUT_SELECTION_CRITERIA_USER)
+                && !(mSelectionCriteria == LAYOUT_SELECTION_CRITERIA_DEVICE)
+                && !(mSelectionCriteria == LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD)
+                && !(mSelectionCriteria == LAYOUT_SELECTION_CRITERIA_DEFAULT)) {
+            throw new java.lang.IllegalArgumentException(
+                    "selectionCriteria was " + mSelectionCriteria + " but must be one of: "
+                            + "LAYOUT_SELECTION_CRITERIA_UNSPECIFIED(" + LAYOUT_SELECTION_CRITERIA_UNSPECIFIED + "), "
+                            + "LAYOUT_SELECTION_CRITERIA_USER(" + LAYOUT_SELECTION_CRITERIA_USER + "), "
+                            + "LAYOUT_SELECTION_CRITERIA_DEVICE(" + LAYOUT_SELECTION_CRITERIA_DEVICE + "), "
+                            + "LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD(" + LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD + "), "
+                            + "LAYOUT_SELECTION_CRITERIA_DEFAULT(" + LAYOUT_SELECTION_CRITERIA_DEFAULT + ")");
+        }
+
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable String getLayoutDescriptor() {
+        return mLayoutDescriptor;
+    }
+
+    @DataClass.Generated.Member
+    public @LayoutSelectionCriteria int getSelectionCriteria() {
+        return mSelectionCriteria;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "KeyboardLayoutSelectionResult { " +
+                "layoutDescriptor = " + mLayoutDescriptor + ", " +
+                "selectionCriteria = " + layoutSelectionCriteriaToString(mSelectionCriteria) +
+        " }";
+    }
+
+    @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(KeyboardLayoutSelectionResult other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        KeyboardLayoutSelectionResult that = (KeyboardLayoutSelectionResult) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && java.util.Objects.equals(mLayoutDescriptor, that.mLayoutDescriptor)
+                && mSelectionCriteria == that.mSelectionCriteria;
+    }
+
+    @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(mLayoutDescriptor);
+        _hash = 31 * _hash + mSelectionCriteria;
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        byte flg = 0;
+        if (mLayoutDescriptor != null) flg |= 0x1;
+        dest.writeByte(flg);
+        if (mLayoutDescriptor != null) dest.writeString(mLayoutDescriptor);
+        dest.writeInt(mSelectionCriteria);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ KeyboardLayoutSelectionResult(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        String layoutDescriptor = (flg & 0x1) == 0 ? null : in.readString();
+        int selectionCriteria = in.readInt();
+
+        this.mLayoutDescriptor = layoutDescriptor;
+        this.mSelectionCriteria = selectionCriteria;
+
+        if (!(mSelectionCriteria == LAYOUT_SELECTION_CRITERIA_UNSPECIFIED)
+                && !(mSelectionCriteria == LAYOUT_SELECTION_CRITERIA_USER)
+                && !(mSelectionCriteria == LAYOUT_SELECTION_CRITERIA_DEVICE)
+                && !(mSelectionCriteria == LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD)
+                && !(mSelectionCriteria == LAYOUT_SELECTION_CRITERIA_DEFAULT)) {
+            throw new java.lang.IllegalArgumentException(
+                    "selectionCriteria was " + mSelectionCriteria + " but must be one of: "
+                            + "LAYOUT_SELECTION_CRITERIA_UNSPECIFIED(" + LAYOUT_SELECTION_CRITERIA_UNSPECIFIED + "), "
+                            + "LAYOUT_SELECTION_CRITERIA_USER(" + LAYOUT_SELECTION_CRITERIA_USER + "), "
+                            + "LAYOUT_SELECTION_CRITERIA_DEVICE(" + LAYOUT_SELECTION_CRITERIA_DEVICE + "), "
+                            + "LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD(" + LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD + "), "
+                            + "LAYOUT_SELECTION_CRITERIA_DEFAULT(" + LAYOUT_SELECTION_CRITERIA_DEFAULT + ")");
+        }
+
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<KeyboardLayoutSelectionResult> CREATOR
+            = new Parcelable.Creator<KeyboardLayoutSelectionResult>() {
+        @Override
+        public KeyboardLayoutSelectionResult[] newArray(int size) {
+            return new KeyboardLayoutSelectionResult[size];
+        }
+
+        @Override
+        public KeyboardLayoutSelectionResult createFromParcel(@NonNull android.os.Parcel in) {
+            return new KeyboardLayoutSelectionResult(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1709568115865L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/core/java/android/hardware/input/KeyboardLayoutSelectionResult.java",
+            inputSignatures = "private final @android.annotation.Nullable java.lang.String mLayoutDescriptor\npublic static final  int LAYOUT_SELECTION_CRITERIA_UNSPECIFIED\npublic static final  int LAYOUT_SELECTION_CRITERIA_USER\npublic static final  int LAYOUT_SELECTION_CRITERIA_DEVICE\npublic static final  int LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD\npublic static final  int LAYOUT_SELECTION_CRITERIA_DEFAULT\npublic static final  android.hardware.input.KeyboardLayoutSelectionResult FAILED\nprivate final @android.hardware.input.KeyboardLayoutSelectionResult.LayoutSelectionCriteria int mSelectionCriteria\nclass KeyboardLayoutSelectionResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genToString=true, genEqualsHashCode=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig b/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig
index 63ae28f..2a11835 100644
--- a/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig
+++ b/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig
@@ -20,3 +20,10 @@
     description: "Enable reporting USB data compliance warnings from HAL when set"
     bug: "296119135"
 }
+
+flag {
+    name: "enable_usb_data_signal_staking"
+    namespace: "preload_safety"
+    description: "Enables signal API with staking"
+    bug: "296119135"
+}
\ No newline at end of file
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index f5b58b9..9dc8c5d 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -453,7 +453,7 @@
 
     @BinderThread
     @Override
-    public void showSoftInput(IBinder showInputToken, @Nullable ImeTracker.Token statsToken,
+    public void showSoftInput(IBinder showInputToken, @NonNull ImeTracker.Token statsToken,
             @InputMethod.ShowFlags int flags, ResultReceiver resultReceiver) {
         ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER);
         mCaller.executeOrSendMessage(mCaller.obtainMessageIOOO(DO_SHOW_SOFT_INPUT,
@@ -462,7 +462,7 @@
 
     @BinderThread
     @Override
-    public void hideSoftInput(IBinder hideInputToken, @Nullable ImeTracker.Token statsToken,
+    public void hideSoftInput(IBinder hideInputToken, @NonNull ImeTracker.Token statsToken,
             int flags, ResultReceiver resultReceiver) {
         ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER);
         mCaller.executeOrSendMessage(mCaller.obtainMessageIOOO(DO_HIDE_SOFT_INPUT,
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 2c7ca27..4dbdd91 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -701,7 +701,13 @@
      */
     private IBinder mCurHideInputToken;
 
-    /** The token tracking the current IME request or {@code null} otherwise. */
+    /**
+     * The token tracking the current IME request.
+     *
+     * <p> This exists as a workaround to changing the signatures of public methods. It will get
+     * set to a {@code non-null} value before every call that uses it, stored locally inside the
+     * callee, and immediately after reset to {@code null} from the callee.
+     */
     @Nullable
     private ImeTracker.Token mCurStatsToken;
 
@@ -907,14 +913,13 @@
         @MainThread
         @Override
         public void hideSoftInputWithToken(int flags, ResultReceiver resultReceiver,
-                IBinder hideInputToken, @Nullable ImeTracker.Token statsToken) {
+                IBinder hideInputToken, @NonNull ImeTracker.Token statsToken) {
             mSystemCallingHideSoftInput = true;
             mCurHideInputToken = hideInputToken;
             mCurStatsToken = statsToken;
             try {
                 hideSoftInput(flags, resultReceiver);
             } finally {
-                mCurStatsToken = null;
                 mCurHideInputToken = null;
                 mSystemCallingHideSoftInput = false;
             }
@@ -926,23 +931,33 @@
         @MainThread
         @Override
         public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
-            ImeTracker.forLogging().onProgress(
-                    mCurStatsToken, ImeTracker.PHASE_IME_HIDE_SOFT_INPUT);
             if (DEBUG) Log.v(TAG, "hideSoftInput()");
+
+            final var statsToken = mCurStatsToken != null ? mCurStatsToken
+                    : createStatsToken(false /* show */,
+                            SoftInputShowHideReason.HIDE_SOFT_INPUT_LEGACY_DIRECT,
+                            ImeTracker.isFromUser(mRootView));
+            mCurStatsToken = null;
+
+            // TODO(b/148086656): Disallow IME developers from calling InputMethodImpl methods.
             if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R
                     && !mSystemCallingHideSoftInput) {
                 Log.e(TAG, "IME shouldn't call hideSoftInput on itself."
                         + " Use requestHideSelf(int) itself");
+                ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_IME_HIDE_SOFT_INPUT);
                 return;
             }
+            ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_HIDE_SOFT_INPUT);
+
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput");
             ImeTracing.getInstance().triggerServiceDump(
                     "InputMethodService.InputMethodImpl#hideSoftInput", mDumper,
                     null /* icProto */);
             final boolean wasVisible = isInputViewShown();
-            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput");
 
             mShowInputFlags = 0;
             mShowInputRequested = false;
+            mCurStatsToken = statsToken;
             hideWindow();
             final boolean isVisible = isInputViewShown();
             final boolean visibilityChanged = isVisible != wasVisible;
@@ -963,14 +978,13 @@
         @Override
         public void showSoftInputWithToken(@InputMethod.ShowFlags int flags,
                 ResultReceiver resultReceiver, IBinder showInputToken,
-                @Nullable ImeTracker.Token statsToken) {
+                @NonNull ImeTracker.Token statsToken) {
             mSystemCallingShowSoftInput = true;
             mCurShowInputToken = showInputToken;
             mCurStatsToken = statsToken;
             try {
                 showSoftInput(flags, resultReceiver);
             } finally {
-                mCurStatsToken = null;
                 mCurShowInputToken = null;
                 mSystemCallingShowSoftInput = false;
             }
@@ -982,16 +996,23 @@
         @MainThread
         @Override
         public void showSoftInput(@InputMethod.ShowFlags int flags, ResultReceiver resultReceiver) {
-            ImeTracker.forLogging().onProgress(
-                    mCurStatsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT);
             if (DEBUG) Log.v(TAG, "showSoftInput()");
+
+            final var statsToken = mCurStatsToken != null ? mCurStatsToken
+                    : createStatsToken(true /* show */,
+                            SoftInputShowHideReason.SHOW_SOFT_INPUT_LEGACY_DIRECT,
+                            ImeTracker.isFromUser(mRootView));
+            mCurStatsToken = null;
+
             // TODO(b/148086656): Disallow IME developers from calling InputMethodImpl methods.
             if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R
                     && !mSystemCallingShowSoftInput) {
-                Log.e(TAG," IME shouldn't call showSoftInput on itself."
+                Log.e(TAG, "IME shouldn't call showSoftInput on itself."
                         + " Use requestShowSelf(int) itself");
+                ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT);
                 return;
             }
+            ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT);
 
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showSoftInput");
             ImeTracing.getInstance().triggerServiceDump(
@@ -999,11 +1020,12 @@
                     null /* icProto */);
             final boolean wasVisible = isInputViewShown();
             if (dispatchOnShowInputRequested(flags, false)) {
-                ImeTracker.forLogging().onProgress(mCurStatsToken,
+                ImeTracker.forLogging().onProgress(statsToken,
                         ImeTracker.PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE);
-                showWindow(true);
+                mCurStatsToken = statsToken;
+                showWindow(true /* showInput */);
             } else {
-                ImeTracker.forLogging().onFailed(mCurStatsToken,
+                ImeTracker.forLogging().onFailed(statsToken,
                         ImeTracker.PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE);
             }
             setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
@@ -1895,21 +1917,23 @@
             if (showingInput) {
                 // If we were last showing the soft keyboard, try to do so again.
                 if (dispatchOnShowInputRequested(showFlags, true)) {
-                    showWindow(true);
+                    showWindowWithToken(true /* showInput */,
+                            SoftInputShowHideReason.RESET_NEW_CONFIGURATION);
                     if (completions != null) {
                         mCurCompletions = completions;
                         onDisplayCompletions(completions);
                     }
                 } else {
-                    hideWindow();
+                    hideWindowWithToken(SoftInputShowHideReason.RESET_NEW_CONFIGURATION);
                 }
             } else if (mCandidatesVisibility == View.VISIBLE) {
                 // If the candidates are currently visible, make sure the
                 // window is shown for them.
-                showWindow(false);
+                showWindowWithToken(false /* showInput */,
+                        SoftInputShowHideReason.RESET_NEW_CONFIGURATION);
             } else {
                 // Otherwise hide the window.
-                hideWindow();
+                hideWindowWithToken(SoftInputShowHideReason.RESET_NEW_CONFIGURATION);
             }
             // If user uses hard keyboard, IME button should always be shown.
             boolean showing = onEvaluateInputViewShown();
@@ -2368,13 +2392,15 @@
             // has not asked for the input view to be shown, then we need
             // to update whether the window is shown.
             if (shown) {
-                showWindow(false);
+                showWindowWithToken(false /* showInput */,
+                        SoftInputShowHideReason.UPDATE_CANDIDATES_VIEW_VISIBILITY);
             } else {
-                hideWindow();
+                hideWindowWithToken(
+                        SoftInputShowHideReason.UPDATE_CANDIDATES_VIEW_VISIBILITY);
             }
         }
     }
-    
+
     void updateCandidatesVisibility(boolean shown) {
         int vis = shown ? View.VISIBLE : getCandidatesHiddenVisibility();
         if (mCandidatesVisibility != vis) {
@@ -3009,6 +3035,19 @@
         return result;
     }
 
+    /**
+     * Utility function that creates an IME request tracking token before
+     * calling {@link #showWindow}.
+     *
+     * @param showInput whether the input window should be shown.
+     * @param reason the reason why the IME request was created.
+     */
+    private void showWindowWithToken(boolean showInput, @SoftInputShowHideReason int reason) {
+        mCurStatsToken = createStatsToken(true /* show */, reason,
+                ImeTracker.isFromUser(mRootView));
+        showWindow(showInput);
+    }
+
     public void showWindow(boolean showInput) {
         if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
                 + " mShowInputRequested=" + mShowInputRequested
@@ -3018,11 +3057,20 @@
                 + " mInputStarted=" + mInputStarted
                 + " mShowInputFlags=" + mShowInputFlags);
 
+        final var statsToken = mCurStatsToken != null ? mCurStatsToken
+                : createStatsToken(true /* show */,
+                        SoftInputShowHideReason.SHOW_WINDOW_LEGACY_DIRECT,
+                        ImeTracker.isFromUser(mRootView));
+        mCurStatsToken = null;
+
         if (mInShowWindow) {
             Log.w(TAG, "Re-entrance in to showWindow");
+            ImeTracker.forLogging().onCancelled(statsToken, ImeTracker.PHASE_IME_SHOW_WINDOW);
             return;
         }
 
+        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_SHOW_WINDOW);
+
         ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", mDumper,
                 null /* icProto */);
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showWindow");
@@ -3046,7 +3094,7 @@
         if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
         mWindow.show();
         mDecorViewWasVisible = true;
-        applyVisibilityInInsetsConsumerIfNecessary(true);
+        applyVisibilityInInsetsConsumerIfNecessary(true /* setVisible */, statsToken);
         cancelImeSurfaceRemoval();
         mInShowWindow = false;
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -3137,13 +3185,15 @@
      * Applies the IME visibility in {@link android.view.ImeInsetsSourceConsumer}.
      *
      * @param setVisible {@code true} to make it visible, false to hide it.
+     * @param statsToken the token tracking the current IME request.
      */
-    private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible) {
+    private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible,
+            @NonNull ImeTracker.Token statsToken) {
         ImeTracing.getInstance().triggerServiceDump(
                 "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", mDumper,
                 null /* icProto */);
         mPrivOps.applyImeVisibilityAsync(setVisible
-                ? mCurShowInputToken : mCurHideInputToken, setVisible, mCurStatsToken);
+                ? mCurShowInputToken : mCurHideInputToken, setVisible, statsToken);
     }
 
     private void finishViews(boolean finishingInput) {
@@ -3159,12 +3209,35 @@
         mCandidatesViewStarted = false;
     }
 
+    /**
+     * Utility function that creates an IME request tracking token before
+     * calling {@link #hideWindow}.
+     *
+     * @param reason the reason why the IME request was created.
+     */
+    private void hideWindowWithToken(@SoftInputShowHideReason int reason) {
+        // TODO(b/303041796): this should be handled by ImeTracker.isFromUser after fixing it
+        //  to work with onClickListeners
+        final boolean isFromUser = ImeTracker.isFromUser(mRootView)
+                || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY;
+        mCurStatsToken = createStatsToken(false /* show */, reason, isFromUser);
+        hideWindow();
+    }
+
     public void hideWindow() {
         if (DEBUG) Log.v(TAG, "CALL: hideWindow");
+
+        final var statsToken = mCurStatsToken != null ? mCurStatsToken
+                : createStatsToken(false /* show */,
+                        SoftInputShowHideReason.HIDE_WINDOW_LEGACY_DIRECT,
+                        ImeTracker.isFromUser(mRootView));
+        mCurStatsToken = null;
+
+        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_HIDE_WINDOW);
         ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", mDumper,
                 null /* icProto */);
         setImeWindowStatus(0, mBackDisposition);
-        applyVisibilityInInsetsConsumerIfNecessary(false);
+        applyVisibilityInInsetsConsumerIfNecessary(false /* setVisible */, statsToken);
         mWindowVisible = false;
         finishViews(false /* finishingInput */);
         if (mDecorViewVisible) {
@@ -3440,9 +3513,14 @@
 
     private void requestHideSelf(@InputMethodManager.HideFlags int flags,
             @SoftInputShowHideReason int reason) {
+        // TODO(b/303041796): this should be handled by ImeTracker.isFromUser after fixing it
+        //  to work with onClickListeners
+        final boolean isFromUser = ImeTracker.isFromUser(mRootView)
+                || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY;
+        final var statsToken = createStatsToken(false /* show */, reason, isFromUser);
         ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", mDumper,
                 null /* icProto */);
-        mPrivOps.hideMySoftInput(flags, reason);
+        mPrivOps.hideMySoftInput(statsToken, flags, reason);
     }
 
     /**
@@ -3450,9 +3528,16 @@
      * interact with it.
      */
     public final void requestShowSelf(@InputMethodManager.ShowFlags int flags) {
+        requestShowSelf(flags, SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME);
+    }
+
+    private void requestShowSelf(@InputMethodManager.ShowFlags int flags,
+            @SoftInputShowHideReason int reason) {
+        final var statsToken = createStatsToken(true /* show */, reason,
+                ImeTracker.isFromUser(mRootView));
         ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", mDumper,
                 null /* icProto */);
-        mPrivOps.showMySoftInput(flags);
+        mPrivOps.showMySoftInput(statsToken, flags, reason);
     }
 
     private boolean handleBack(boolean doIt) {
@@ -3472,7 +3557,7 @@
                 // If we have the window visible for some other reason --
                 // most likely to show candidates -- then just get rid
                 // of it.  This really shouldn't happen, but just in case...
-                if (doIt) hideWindow();
+                if (doIt) hideWindowWithToken(SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY);
             }
             return true;
         }
@@ -3627,10 +3712,11 @@
             @InputMethodManager.HideFlags int hideFlags) {
         if (DEBUG) Log.v(TAG, "toggleSoftInput()");
         if (isInputViewShown()) {
-            requestHideSelf(
-                    hideFlags, SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT);
+            requestHideSelf(hideFlags,
+                    SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT);
         } else {
-            requestShowSelf(showFlags);
+            requestShowSelf(showFlags,
+                    SoftInputShowHideReason.SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT);
         }
     }
     
@@ -4272,6 +4358,20 @@
     }
 
     /**
+     * Creates an IME request tracking token.
+     *
+     * @param show whether this is a show or a hide request.
+     * @param reason the reason why the IME request was created.
+     * @param isFromUser whether this request was created directly from user interaction.
+     */
+    @NonNull
+    private ImeTracker.Token createStatsToken(boolean show, @SoftInputShowHideReason int reason,
+            boolean isFromUser) {
+        return ImeTracker.forLogging().onStart(show ? ImeTracker.TYPE_SHOW : ImeTracker.TYPE_HIDE,
+                ImeTracker.ORIGIN_IME, reason, isFromUser);
+    }
+
+    /**
      * 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/navigationbar/NavigationBarView.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
index 510b14e..e28f345 100644
--- a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
+++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
@@ -99,7 +99,11 @@
 
         mDeadZone = new android.inputmethodservice.navigationbar.DeadZone(this);
 
-        getImeSwitchButton().setOnClickListener(view -> view.getContext()
+        getBackButton().setLongClickable(false);
+
+        final ButtonDispatcher imeSwitchButton = getImeSwitchButton();
+        imeSwitchButton.setLongClickable(false);
+        imeSwitchButton.setOnClickListener(view -> view.getContext()
                 .getSystemService(InputMethodManager.class).showInputMethodPicker());
     }
 
diff --git a/core/java/android/net/flags.aconfig b/core/java/android/net/flags.aconfig
index 6efb872..9f9aef8 100644
--- a/core/java/android/net/flags.aconfig
+++ b/core/java/android/net/flags.aconfig
@@ -17,3 +17,9 @@
     bug: "307898240"
 }
 
+flag {
+  name: "register_nsd_offload_engine"
+  namespace: "android_core_networking"
+  description: "Flag for registerOffloadEngine API in NsdManager"
+  bug: "294777050"
+}
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index 05a1abea..b417534 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -240,7 +240,7 @@
             new Dimensions(POWER_COMPONENT_ANY, PROCESS_STATE_ANY);
 
     /**
-     * Identifies power attribution dimensions that are captured by an data element of
+     * Identifies power attribution dimensions that are captured by a data element of
      * a BatteryConsumer. These Keys are used to access those values and to set them using
      * Builders.  See for example {@link #getConsumedPower(Key)}.
      *
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index e090942..c611cb9 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1587,7 +1587,7 @@
                 outNumOfInterest[0] = numOfInterest;
             }
 
-            // The estimated time is the average time we spend in each level, multipled
+            // The estimated time is the average time we spend in each level, multiplied
             // by 100 -- the total number of battery levels
             return (total / numOfInterest) * 100;
         }
@@ -2019,7 +2019,7 @@
         public static final int EVENT_TOP = 0x0003;
         // Event is about active sync operations.
         public static final int EVENT_SYNC = 0x0004;
-        // Events for all additional wake locks aquired/release within a wake block.
+        // Events for all additional wake locks acquired/release within a wake block.
         // These are not generated by default.
         public static final int EVENT_WAKE_LOCK = 0x0005;
         // Event is about an application executing a scheduled job.
@@ -3419,7 +3419,7 @@
      * incoming service calls from apps.  The result is returned as an array of longs,
      * organized as a sequence like this:
      * <pre>
-     *     cluster1-speeed1, cluster1-speed2, ..., cluster2-speed1, cluster2-speed2, ...
+     *     cluster1-speed1, cluster1-speed2, ..., cluster2-speed1, cluster2-speed2, ...
      * </pre>
      *
      * @see com.android.internal.os.CpuScalingPolicies#getPolicies
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 3149de4..beb9a93 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -120,7 +120,6 @@
     private ClassLoader mClassLoader;
     private String mLibrarySearchPaths;
     private String mLibraryPermittedPaths;
-    private GameManager mGameManager;
 
     private int mAngleOptInIndex = -1;
     private boolean mShouldUseAngle = false;
@@ -134,8 +133,6 @@
         final ApplicationInfo appInfoWithMetaData =
                 getAppInfoWithMetadata(context, pm, packageName);
 
-        mGameManager = context.getSystemService(GameManager.class);
-
         Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers");
         setupGpuLayers(context, coreSettings, pm, packageName, appInfoWithMetaData);
         Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
@@ -161,9 +158,11 @@
         Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
 
         Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "notifyGraphicsEnvironmentSetup");
-        if (mGameManager != null
-                && appInfoWithMetaData.category == ApplicationInfo.CATEGORY_GAME) {
-            mGameManager.notifyGraphicsEnvironmentSetup();
+        if (appInfoWithMetaData.category == ApplicationInfo.CATEGORY_GAME) {
+            final GameManager gameManager = context.getSystemService(GameManager.class);
+            if (gameManager != null) {
+                gameManager.notifyGraphicsEnvironmentSetup();
+            }
         }
         Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
     }
diff --git a/core/java/android/os/HandlerThread.java b/core/java/android/os/HandlerThread.java
index 36730cb..f852d3c 100644
--- a/core/java/android/os/HandlerThread.java
+++ b/core/java/android/os/HandlerThread.java
@@ -19,6 +19,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 
+import java.util.concurrent.Executor;
+
 /**
  * A {@link Thread} that has a {@link Looper}.
  * The {@link Looper} can then be used to create {@link Handler}s.
@@ -30,7 +32,8 @@
     int mPriority;
     int mTid = -1;
     Looper mLooper;
-    private @Nullable Handler mHandler;
+    private volatile @Nullable Handler mHandler;
+    private volatile @Nullable Executor mExecutor;
 
     public HandlerThread(String name) {
         super(name);
@@ -131,6 +134,18 @@
     }
 
     /**
+     * @return a shared {@link Executor} associated with this thread
+     * @hide
+     */
+    @NonNull
+    public Executor getThreadExecutor() {
+        if (mExecutor == null) {
+            mExecutor = new HandlerExecutor(getThreadHandler());
+        }
+        return mExecutor;
+    }
+
+    /**
      * Quits the handler thread's looper.
      * <p>
      * Causes the handler thread's looper to terminate without processing any
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index 9fd37d4..fb500a9 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -618,7 +618,7 @@
      */
     @FastNative
     @NonNull
-    public native final @Nullable
+    public native final
     HidlMemory readEmbeddedHidlMemory(long fieldHandle, long parentHandle, long offset);
 
     /**
diff --git a/core/java/android/os/IVibratorManagerService.aidl b/core/java/android/os/IVibratorManagerService.aidl
index 65e498e..8b1577c 100644
--- a/core/java/android/os/IVibratorManagerService.aidl
+++ b/core/java/android/os/IVibratorManagerService.aidl
@@ -41,5 +41,5 @@
     // There is no order guarantee with respect to the two-way APIs above like
     // vibrate/isVibrating/cancel.
     oneway void performHapticFeedback(int uid, int deviceId, String opPkg, int constant,
-            boolean always, String reason);
+            boolean always, String reason, boolean fromIme);
 }
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index 3950c25..2fe115f 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -623,14 +623,14 @@
                 // Message is to be inserted at tail or middle of queue. Usually we don't have to
                 // wake up the event queue unless there is a barrier at the head of the queue and
                 // the message is the earliest asynchronous message in the queue.
-                //
+                needWake = mBlocked && p.target == null && msg.isAsynchronous();
+
                 // For readability, we split this portion of the function into two blocks based on
                 // whether tail tracking is enabled. This has a minor implication for the case
                 // where tail tracking is disabled. See the comment below.
                 if (Flags.messageQueueTailTracking()) {
-                    needWake = mBlocked && p.target == null && msg.isAsynchronous()
-                        && mAsyncMessageCount == 0;
                     if (when >= mLast.when) {
+                        needWake = needWake && mAsyncMessageCount == 0;
                         msg.next = null;
                         mLast.next = msg;
                         mLast = msg;
@@ -643,6 +643,9 @@
                             if (p == null || when < p.when) {
                                 break;
                             }
+                            if (needWake && p.isAsynchronous()) {
+                                needWake = false;
+                            }
                         }
                         if (p == null) {
                             /* Inserting at tail of queue */
@@ -652,7 +655,6 @@
                         prev.next = msg;
                     }
                 } else {
-                    needWake = mBlocked && p.target == null && msg.isAsynchronous();
                     Message prev;
                     for (;;) {
                         prev = p;
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index 04c257b..2a62c24 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -206,12 +206,13 @@
     }
 
     @Override
-    public void performHapticFeedback(int constant, boolean always, String reason) {
+    public void performHapticFeedback(
+            int constant, boolean always, String reason, boolean fromIme) {
         if (mVibratorManager == null) {
             Log.w(TAG, "Failed to perform haptic feedback; no vibrator manager.");
             return;
         }
-        mVibratorManager.performHapticFeedback(constant, always, reason);
+        mVibratorManager.performHapticFeedback(constant, always, reason, fromIme);
     }
 
     @Override
diff --git a/core/java/android/os/SystemVibratorManager.java b/core/java/android/os/SystemVibratorManager.java
index 8e83923..c80bcac 100644
--- a/core/java/android/os/SystemVibratorManager.java
+++ b/core/java/android/os/SystemVibratorManager.java
@@ -147,14 +147,15 @@
     }
 
     @Override
-    public void performHapticFeedback(int constant, boolean always, String reason) {
+    public void performHapticFeedback(int constant, boolean always, String reason,
+            boolean fromIme) {
         if (mService == null) {
             Log.w(TAG, "Failed to perform haptic feedback; no vibrator manager service.");
             return;
         }
         try {
             mService.performHapticFeedback(
-                    mUid, mContext.getDeviceId(), mPackageName, constant, always, reason);
+                    mUid, mContext.getDeviceId(), mPackageName, constant, always, reason, fromIme);
         } catch (RemoteException e) {
             Log.w(TAG, "Failed to perform haptic feedback.", e);
         }
@@ -244,8 +245,9 @@
         }
 
         @Override
-        public void performHapticFeedback(int effectId, boolean always, String reason) {
-            SystemVibratorManager.this.performHapticFeedback(effectId, always, reason);
+        public void performHapticFeedback(int effectId, boolean always, String reason,
+                boolean fromIme) {
+            SystemVibratorManager.this.performHapticFeedback(effectId, always, reason, fromIme);
         }
 
         @Override
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index be17d7c..9757a10 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1920,9 +1920,7 @@
      * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
-    // TODO (b/325886480): update the flag to
-    // "com.android.net.thread.platform.flags.Flags.FLAG_THREAD_USER_RESTRICTION_ENABLED"
-    @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled")
+    @FlaggedApi(com.android.net.thread.platform.flags.Flags.FLAG_THREAD_USER_RESTRICTION_ENABLED)
     public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
 
     /**
@@ -4710,6 +4708,9 @@
      * Sets the user as enabled, if such an user exists.
      *
      * <p>Note that the default is true, it's only that managed profiles might not be enabled.
+     * (Managed profiles created by DevicePolicyManager will start out disabled, and DPM will later
+     * toggle them to enabled once they are provisioned. This is the primary purpose of the
+     * {@link UserInfo#FLAG_DISABLED} flag.)
      * Also ephemeral users can be disabled to indicate that their removal is in progress and they
      * shouldn't be re-entered. Therefore ephemeral users should not be re-enabled once disabled.
      *
@@ -5261,7 +5262,7 @@
 
     /**
      * Returns list of the profiles of userId including userId itself.
-     * Note that this returns only enabled.
+     * Note that this returns only {@link UserInfo#isEnabled() enabled} profiles.
      * <p>Note that this includes all profile types (not including Restricted profiles).
      *
      * <p>Requires {@link android.Manifest.permission#MANAGE_USERS} or
diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java
index 46705a3..9df5b85 100644
--- a/core/java/android/os/VibrationAttributes.java
+++ b/core/java/android/os/VibrationAttributes.java
@@ -289,6 +289,15 @@
     }
 
     /**
+     * Return the original {@link AudioAttributes} used to create the vibration attributes.
+     * @hide
+     */
+    @AudioAttributes.AttributeUsage
+    public int getOriginalAudioUsage() {
+        return mOriginalAudioUsage;
+    }
+
+    /**
      * Return the flags.
      * @return a combined mask of all flags
      */
@@ -405,8 +414,8 @@
         return "VibrationAttributes{"
                 + "mUsage=" + usageToString()
                 + ", mAudioUsage= " + AudioAttributes.usageToString(mOriginalAudioUsage)
-                + ", mFlags=" + mFlags
                 + ", mCategory=" + categoryToString()
+                + ", mFlags=" + mFlags
                 + '}';
     }
 
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 2fc2414..4b2d4eb 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -534,10 +534,12 @@
      *          {@code false} if the vibration for the haptic feedback should respect the applicable
      *          vibration intensity settings.
      * @param reason the reason for this haptic feedback.
+     * @param fromIme the haptic feedback is performed from an IME.
      *
      * @hide
      */
-    public void performHapticFeedback(int constant, boolean always, String reason) {
+    public void performHapticFeedback(int constant, boolean always, String reason,
+            boolean fromIme) {
         Log.w(TAG, "performHapticFeedback is not supported");
     }
 
diff --git a/core/java/android/os/VibratorManager.java b/core/java/android/os/VibratorManager.java
index e0b6a9f..513c4bd 100644
--- a/core/java/android/os/VibratorManager.java
+++ b/core/java/android/os/VibratorManager.java
@@ -146,9 +146,11 @@
      *          vibration intensity settings applicable to the corresponding vibration.
      *          {@code false} otherwise.
      * @param reason the reason for this haptic feedback.
+     * @param fromIme the haptic feedback is performed from an IME.
      * @hide
      */
-    public void performHapticFeedback(int constant, boolean always, String reason) {
+    public void performHapticFeedback(int constant, boolean always, String reason,
+            boolean fromIme) {
         Log.w(TAG, "performHapticFeedback is not supported");
     }
 
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index abfa4e3..d9400ac 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -1,4 +1,5 @@
 package: "android.os"
+container: "system"
 
 flag {
     name: "android_os_build_vanilla_ice_cream"
@@ -40,6 +41,7 @@
     namespace: "profile_experiences"
     description: "Guards a new Private Profile type in UserManager - everything from its setup to config to deletion."
     bug: "299069460"
+    is_exported: true
 }
 
 flag {
diff --git a/core/java/android/os/health/HealthStatsWriter.java b/core/java/android/os/health/HealthStatsWriter.java
index d4d10b0..4118775 100644
--- a/core/java/android/os/health/HealthStatsWriter.java
+++ b/core/java/android/os/health/HealthStatsWriter.java
@@ -58,7 +58,7 @@
      * Construct a HealthStatsWriter object with the given constants.
      *
      * The "getDataType()" of the resulting HealthStats object will be the
-     * short name of the java class that the Constants object was initalized
+     * short name of the java class that the Constants object was initialized
      * with.
      */
     public HealthStatsWriter(HealthKeys.Constants constants) {
diff --git a/core/java/android/os/image/DynamicSystemClient.java b/core/java/android/os/image/DynamicSystemClient.java
index 88096ab..ada708b 100644
--- a/core/java/android/os/image/DynamicSystemClient.java
+++ b/core/java/android/os/image/DynamicSystemClient.java
@@ -52,7 +52,7 @@
  *
  * After the installation is completed, the device will be running in the new system on next the
  * reboot. Then, when the user reboots the device again, it will leave {@code DynamicSystem} and go
- * back to the original system. While running in {@code DynamicSystem}, persitent storage for
+ * back to the original system. While running in {@code DynamicSystem}, persistent storage for
  * factory reset protection (FRP) remains unchanged. Since the user is running the new system with
  * a temporarily created data partition, their original user data are kept unchanged.</p>
  *
diff --git a/core/java/android/os/image/DynamicSystemManager.java b/core/java/android/os/image/DynamicSystemManager.java
index 536795b..8ce87e9 100644
--- a/core/java/android/os/image/DynamicSystemManager.java
+++ b/core/java/android/os/image/DynamicSystemManager.java
@@ -172,7 +172,7 @@
         }
     }
     /**
-     * Finish a previously started installation. Installations without a cooresponding
+     * Finish a previously started installation. Installations without a corresponding
      * finishInstallation() will be cleaned up during device boot.
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS
index 2cb16d337b..c21895a 100644
--- a/core/java/android/os/storage/OWNERS
+++ b/core/java/android/os/storage/OWNERS
@@ -3,11 +3,15 @@
 # PLEASE ASSIGN NEW BUGS TO android-storage-triage@, NOT TO INDIVIDUAL PEOPLE
 
 # Android Storage Team
+aibra@google.com
+akgaurav@google.com
 alukin@google.com
 ankitavyas@google.com
 dipankarb@google.com
 gargshivam@google.com
+ishneet@google.com
 krishang@google.com
+oeissa@google.com
 riyaghai@google.com
 sahanas@google.com
 shikhamalhotra@google.com
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 5a09541..d45a17f 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1395,7 +1395,7 @@
                 // Package name can be null if the activity thread is running but the app
                 // hasn't bound yet. In this case we fall back to the first package in the
                 // current UID. This works for runtime permissions as permission state is
-                // per UID and permission realted app ops are updated for all UID packages.
+                // per UID and permission related app ops are updated for all UID packages.
                 String[] packageNames = ActivityThread.getPackageManager().getPackagesForUid(
                         android.os.Process.myUid());
                 if (packageNames == null || packageNames.length <= 0) {
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index e1f112a..4cf2fd4 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -62,7 +62,7 @@
  * <li>To get access to standard directories (like the {@link Environment#DIRECTORY_PICTURES}), they
  * can use the {@link #createAccessIntent(String)}. This is the recommend way, since it provides a
  * simpler API and narrows the access to the given directory (and its descendants).
- * <li>To get access to any directory (and its descendants), they can use the Storage Acess
+ * <li>To get access to any directory (and its descendants), they can use the Storage Access
  * Framework APIs (such as {@link Intent#ACTION_OPEN_DOCUMENT} and
  * {@link Intent#ACTION_OPEN_DOCUMENT_TREE}, although these APIs do not guarantee the user will
  * select this specific volume.
diff --git a/core/java/android/os/vibrator/VibrationConfig.java b/core/java/android/os/vibrator/VibrationConfig.java
index bcdb982..a14a2c7 100644
--- a/core/java/android/os/vibrator/VibrationConfig.java
+++ b/core/java/android/os/vibrator/VibrationConfig.java
@@ -224,17 +224,19 @@
     @Override
     public String toString() {
         return "VibrationConfig{"
-                + "mHapticChannelMaxVibrationAmplitude=" + mHapticChannelMaxVibrationAmplitude
+                + "mIgnoreVibrationsOnWirelessCharger=" + mIgnoreVibrationsOnWirelessCharger
+                + ", mHapticChannelMaxVibrationAmplitude=" + mHapticChannelMaxVibrationAmplitude
                 + ", mRampStepDurationMs=" + mRampStepDurationMs
                 + ", mRampDownDurationMs=" + mRampDownDurationMs
+                + ", mRequestVibrationParamsForUsages="
+                + Arrays.toString(getRequestVibrationParamsForUsagesNames())
+                + ", mRequestVibrationParamsTimeoutMs=" + mRequestVibrationParamsTimeoutMs
                 + ", mDefaultAlarmIntensity=" + mDefaultAlarmVibrationIntensity
                 + ", mDefaultHapticFeedbackIntensity=" + mDefaultHapticFeedbackIntensity
                 + ", mDefaultMediaIntensity=" + mDefaultMediaVibrationIntensity
                 + ", mDefaultNotificationIntensity=" + mDefaultNotificationVibrationIntensity
                 + ", mDefaultRingIntensity=" + mDefaultRingVibrationIntensity
-                + ", mRequestVibrationParamsTimeoutMs=" + mRequestVibrationParamsTimeoutMs
-                + ", mRequestVibrationParamsForUsages=" + Arrays.toString(
-                getRequestVibrationParamsForUsagesNames())
+                + ", mDefaultKeyboardVibrationEnabled=" + mDefaultKeyboardVibrationEnabled
                 + "}";
     }
 
@@ -246,9 +248,13 @@
     public void dumpWithoutDefaultSettings(IndentingPrintWriter pw) {
         pw.println("VibrationConfig:");
         pw.increaseIndent();
+        pw.println("ignoreVibrationsOnWirelessCharger = " + mIgnoreVibrationsOnWirelessCharger);
         pw.println("hapticChannelMaxAmplitude = " + mHapticChannelMaxVibrationAmplitude);
         pw.println("rampStepDurationMs = " + mRampStepDurationMs);
         pw.println("rampDownDurationMs = " + mRampDownDurationMs);
+        pw.println("requestVibrationParamsForUsages = "
+                + Arrays.toString(getRequestVibrationParamsForUsagesNames()));
+        pw.println("requestVibrationParamsTimeoutMs = " + mRequestVibrationParamsTimeoutMs);
         pw.decreaseIndent();
     }
 
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 8495f37..410f510 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -247,8 +247,6 @@
 
     private final LegacyPermissionManager mLegacyPermissionManager;
 
-    private final VirtualDeviceManager mVirtualDeviceManager;
-
     private final ArrayMap<PackageManager.OnPermissionsChangedListener,
             IOnPermissionsChangeListener> mPermissionListeners = new ArrayMap<>();
     private PermissionUsageHelper mUsageHelper;
@@ -269,7 +267,6 @@
         mPermissionManager = IPermissionManager.Stub.asInterface(ServiceManager.getServiceOrThrow(
                 "permissionmgr"));
         mLegacyPermissionManager = context.getSystemService(LegacyPermissionManager.class);
-        mVirtualDeviceManager = context.getSystemService(VirtualDeviceManager.class);
     }
 
     /**
@@ -1791,6 +1788,9 @@
 
     /**
      * Gets the permission states for requested package and persistent device.
+     * <p>
+     * <strong>Note: </strong>Default device permissions are not inherited in this API. Returns the
+     * exact permission states for the requested device.
      *
      * @param packageName name of the package you are checking against
      * @param persistentDeviceId id of the persistent device you are checking against
@@ -1918,14 +1918,18 @@
         if (deviceId == Context.DEVICE_ID_DEFAULT) {
             persistentDeviceId = VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT;
         } else if (android.companion.virtual.flags.Flags.vdmPublicApis()) {
-            VirtualDevice virtualDevice = mVirtualDeviceManager.getVirtualDevice(deviceId);
-            if (virtualDevice == null) {
-                Slog.e(LOG_TAG, "Virtual device is not found with device Id " + deviceId);
-                return null;
-            }
-            persistentDeviceId = virtualDevice.getPersistentDeviceId();
-            if (persistentDeviceId == null) {
-                Slog.e(LOG_TAG, "Cannot find persistent device Id for " + deviceId);
+            VirtualDeviceManager virtualDeviceManager = mContext.getSystemService(
+                    VirtualDeviceManager.class);
+            if (virtualDeviceManager != null) {
+                VirtualDevice virtualDevice = virtualDeviceManager.getVirtualDevice(deviceId);
+                if (virtualDevice == null) {
+                    Slog.e(LOG_TAG, "Virtual device is not found with device Id " + deviceId);
+                    return null;
+                }
+                persistentDeviceId = virtualDevice.getPersistentDeviceId();
+                if (persistentDeviceId == null) {
+                    Slog.e(LOG_TAG, "Cannot find persistent device Id for " + deviceId);
+                }
             }
         } else {
             Slog.e(LOG_TAG, "vdmPublicApis flag is not enabled when device Id " + deviceId
@@ -2072,5 +2076,29 @@
                 return new PermissionState[size];
             }
         };
+
+        /** @hide */
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            PermissionState that = (PermissionState) o;
+            return mGranted == that.mGranted && mFlags == that.mFlags;
+        }
+
+        /** @hide */
+        @Override
+        public int hashCode() {
+            return Objects.hash(mGranted, mFlags);
+        }
+
+        /** @hide */
+        @Override
+        public String toString() {
+            return "PermissionState{"
+                    + "mGranted=" + mGranted
+                    + ", mFlags=" + mFlags
+                    + '}';
+        }
     }
 }
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 460b4dd..141ffc9 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -359,8 +359,7 @@
                         new PermissionGroupUsage(usage.packageName, usage.uid, usage.lastAccessTime,
                                 permGroup,
                                 usage.isRunning, isPhone, usage.attributionTag, attributionLabel,
-                                usagesWithLabels.valueAt(usageNum),
-                                VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT));
+                                usagesWithLabels.valueAt(usageNum), deviceId));
             }
         }
 
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index c13dd36..c03dc71 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -406,6 +406,7 @@
          * Builder for the add-call parameters.
          */
         public static final class AddCallParametersBuilder {
+            public static final int MAX_NUMBER_OF_CHARACTERS = 256;
             private CallerInfo mCallerInfo;
             private String mNumber;
             private String mPostDialDigits;
@@ -431,7 +432,7 @@
             private Uri mPictureUri;
             private int mIsPhoneAccountMigrationPending;
             private boolean mIsBusinessCall;
-            private String mBusinessName;
+            private String mAssertedDisplayName;
 
             /**
              * @param callerInfo the CallerInfo object to get the target contact from.
@@ -659,11 +660,18 @@
             }
 
             /**
-             * @param businessName should be set if the caller is a business call
+             * @param assertedDisplayName the asserted display name associated with the business
+             *                            call
+             * @throws IllegalArgumentException if the assertedDisplayName is over 256 characters
              */
             @FlaggedApi(Flags.FLAG_BUSINESS_CALL_COMPOSER)
-            public @NonNull AddCallParametersBuilder setBusinessName(String businessName) {
-                mBusinessName = businessName;
+            public @NonNull AddCallParametersBuilder setAssertedDisplayName(
+                    String assertedDisplayName) {
+                if (assertedDisplayName.length() > MAX_NUMBER_OF_CHARACTERS) {
+                    throw new IllegalArgumentException("assertedDisplayName exceeds the character"
+                            + " limit of " + MAX_NUMBER_OF_CHARACTERS + ".");
+                }
+                mAssertedDisplayName = assertedDisplayName;
                 return this;
             }
 
@@ -678,7 +686,7 @@
                             mCallBlockReason,
                             mCallScreeningAppName, mCallScreeningComponentName, mMissedReason,
                             mPriority, mSubject, mLatitude, mLongitude, mPictureUri,
-                            mIsPhoneAccountMigrationPending, mIsBusinessCall, mBusinessName);
+                            mIsPhoneAccountMigrationPending, mIsBusinessCall, mAssertedDisplayName);
                 } else {
                     return new AddCallParams(mCallerInfo, mNumber, mPostDialDigits, mViaNumber,
                             mPresentation, mCallType, mFeatures, mAccountHandle, mStart, mDuration,
@@ -716,7 +724,7 @@
         private Uri mPictureUri;
         private int mIsPhoneAccountMigrationPending;
         private boolean mIsBusinessCall;
-        private String mBusinessName;
+        private String mAssertedDisplayName;
 
         private AddCallParams(CallerInfo callerInfo, String number, String postDialDigits,
                 String viaNumber, int presentation, int callType, int features,
@@ -761,7 +769,8 @@
                 CharSequence callScreeningAppName, String callScreeningComponentName,
                 long missedReason,
                 int priority, String subject, double latitude, double longitude, Uri pictureUri,
-                int isPhoneAccountMigrationPending, boolean isBusinessCall, String businessName) {
+                int isPhoneAccountMigrationPending, boolean isBusinessCall,
+                String assertedDisplayName) {
             mCallerInfo = callerInfo;
             mNumber = number;
             mPostDialDigits = postDialDigits;
@@ -787,7 +796,7 @@
             mPictureUri = pictureUri;
             mIsPhoneAccountMigrationPending = isPhoneAccountMigrationPending;
             mIsBusinessCall = isBusinessCall;
-            mBusinessName = businessName;
+            mAssertedDisplayName = assertedDisplayName;
         }
 
     }
@@ -1833,7 +1842,7 @@
             values.put(IS_PHONE_ACCOUNT_MIGRATION_PENDING, params.mIsPhoneAccountMigrationPending);
             if (Flags.businessCallComposer()) {
                 values.put(IS_BUSINESS_CALL, Integer.valueOf(params.mIsBusinessCall ? 1 : 0));
-                values.put(ASSERTED_DISPLAY_NAME, params.mBusinessName);
+                values.put(ASSERTED_DISPLAY_NAME, params.mAssertedDisplayName);
             }
             if ((params.mCallerInfo != null) && (params.mCallerInfo.getContactId() > 0)) {
                 // Update usage information for the number associated with the contact ID.
diff --git a/core/java/android/provider/ContactKeysManager.java b/core/java/android/provider/E2eeContactKeysManager.java
similarity index 60%
rename from core/java/android/provider/ContactKeysManager.java
rename to core/java/android/provider/E2eeContactKeysManager.java
index 01aaa3d..09c93e3 100644
--- a/core/java/android/provider/ContactKeysManager.java
+++ b/core/java/android/provider/E2eeContactKeysManager.java
@@ -39,18 +39,18 @@
 import java.util.Objects;
 
 /**
- * ContactKeysManager provides access to the provider of end-to-end encryption contact keys.
- * It manages two types of keys - {@link ContactKey} and {@link SelfKey}.
+ * E2eeContactKeysManager provides access to the provider of end-to-end encryption contact keys.
+ * It manages two types of keys - {@link E2eeContactKey} and {@link E2eeSelfKey}.
  * <ul>
  * <li>
- * A {@link ContactKey} is a public key associated with a contact. It's used to end-to-end
+ * A {@link E2eeContactKey} is a public key associated with a contact. It's used to end-to-end
  * encrypt the communications between a user and the contact. This API allows operations on
- * {@link ContactKey}s to insert/update, remove, change the verification state, and retrieving
+ * {@link E2eeContactKey}s to insert/update, remove, change the verification state, and retrieving
  * keys (either created by or visible to the caller app).
  * </li>
  * <li>
- * A {@link SelfKey} is a key for this device, so the key represents the owner of the device.
- * This API allows operations on {@link SelfKey}s to insert/update, remove, and retrieving
+ * A {@link E2eeSelfKey} is a key for this device, so the key represents the owner of the device.
+ * This API allows operations on {@link E2eeSelfKey}s to insert/update, remove, and retrieving
  * self keys (either created by or visible to the caller app).
  * </li>
  * </ul>
@@ -65,29 +65,32 @@
  * </li>
  * <li>
  * accountId - the app-specified identifier for the account for which the contact key can be used.
- * Usually a phone number.
+ * Using different account IDs allows for multiple key entries representing the same user.
+ * For most apps this would be a phone number.
  * </li>
  * </ul>
  * Contact keys also use lookupKey which is an opaque value used to identify a contact in
  * ContactsProvider.
  */
 @FlaggedApi(Flags.FLAG_USER_KEYS)
-public final class ContactKeysManager {
+public final class E2eeContactKeysManager {
     /**
-     * The authority for the contact keys provider.
+     * The authority for the end-to-end encryption contact keys provider.
+     *
      * @hide
      */
     public static final String AUTHORITY = "com.android.contactkeys.contactkeysprovider";
 
     /**
-     * A content:// style uri to the authority for the contact keys provider.
+     * A content:// style uri to the authority for the end-to-end encryption contact keys provider.
+     *
      * @hide
      */
     @NonNull
     public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
 
     /**
-     * Maximum size of a contact key.
+     * Maximum size of an end-to-end encryption contact key.
      */
     private static final int MAX_KEY_SIZE_BYTES = 5000;
 
@@ -100,91 +103,91 @@
     private final ContentResolver mContentResolver;
 
     /** @hide */
-    public ContactKeysManager(@NonNull Context context) {
+    public E2eeContactKeysManager(@NonNull Context context) {
         Objects.requireNonNull(context);
         mContentResolver = context.getContentResolver();
     }
 
     /**
-     * Inserts a new entry into the contact keys table or updates one if it already exists.
-     * The inserted/updated contact key is owned by the caller app.
+     * Inserts a new entry into the end-to-end encryption contact keys table or updates one if it
+     * already exists.
+     * The inserted/updated end-to-end encryption contact key is owned by the caller app.
      *
      * @param lookupKey value that references the contact
-     * @param deviceId an app-specified identifier for the device
+     * @param deviceId  an app-specified identifier for the device
      * @param accountId an app-specified identifier for the account
-     * @param keyValue the raw bytes for the key (max size is {@link #getMaxKeySizeBytes} bytes)
+     * @param keyValue  the raw bytes for the key (max size is {@link #getMaxKeySizeBytes} bytes)
      */
     @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
-    public void updateOrInsertContactKey(@NonNull String lookupKey,
+    public void updateOrInsertE2eeContactKey(@NonNull String lookupKey,
             @NonNull String deviceId,
             @NonNull String accountId,
             @NonNull byte[] keyValue) {
         validateKeyLength(keyValue);
 
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
-        extras.putByteArray(ContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue));
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putByteArray(E2eeContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue));
 
         nullSafeCall(mContentResolver,
-                ContactKeys.UPDATE_OR_INSERT_CONTACT_KEY_METHOD, extras);
+                E2eeContactKeys.UPDATE_OR_INSERT_CONTACT_KEY_METHOD, extras);
     }
 
     /**
-     * Retrieves a contact key entry given the lookup key, device ID, accountId and inferred
-     * caller package name.
+     * Retrieves an end-to-end encryption contact key entry given the lookup key, device ID,
+     * accountId and inferred caller package name.
      *
      * @param lookupKey the value that references the contact
-     * @param deviceId an app-specified identifier for the device
+     * @param deviceId  an app-specified identifier for the device
      * @param accountId an app-specified identifier for the account
-     *
-     * @return a {@link ContactKey} object containing the contact key information,
+     * @return a {@link E2eeContactKey} object containing the contact key information,
      * or null if no contact key is found.
      */
     @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
     @Nullable
-    public ContactKey getContactKey(
+    public E2eeContactKey getE2eeContactKey(
             @NonNull String lookupKey,
             @NonNull String deviceId,
             @NonNull String accountId) {
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.GET_CONTACT_KEY_METHOD, extras);
+                E2eeContactKeys.GET_CONTACT_KEY_METHOD, extras);
 
         if (response == null) {
             return null;
         }
-        return response.getParcelable(ContactKeys.KEY_CONTACT_KEY, ContactKey.class);
+        return response.getParcelable(E2eeContactKeys.KEY_CONTACT_KEY, E2eeContactKey.class);
     }
 
     /**
-     * Retrieves all contact key entries that belong to apps visible to the caller.
+     * Retrieves all end-to-end encryption contact key entries that belong to apps visible to
+     * the caller.
      * The keys will be stripped of deviceId, timeUpdated and keyValue data.
      *
      * @param lookupKey the value that references the contact
-     *
-     * @return a list of {@link ContactKey} objects containing the contact key
+     * @return a list of {@link E2eeContactKey} objects containing the contact key
      * information, or an empty list if no keys are found.
      */
     @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
     @NonNull
-    public List<ContactKey> getAllContactKeys(@NonNull String lookupKey) {
+    public List<E2eeContactKey> getAllE2eeContactKeys(@NonNull String lookupKey) {
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.GET_ALL_CONTACT_KEYS_METHOD, extras);
+                E2eeContactKeys.GET_ALL_CONTACT_KEYS_METHOD, extras);
 
         if (response == null) {
             return new ArrayList<>();
         }
-        List<ContactKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS,
-                ContactKey.class);
+        List<E2eeContactKey> value = response.getParcelableArrayList(
+                E2eeContactKeys.KEY_CONTACT_KEYS, E2eeContactKey.class);
         if (value == null) {
             return new ArrayList<>();
         }
@@ -192,27 +195,27 @@
     }
 
     /**
-     * Retrieves all contact key entries for a given lookupKey that belong to the caller app.
+     * Retrieves all end-to-end encryption contact key entries for a given lookupKey that belong to
+     * the caller app.
      *
      * @param lookupKey the value that references the contact
-     *
-     * @return a list of {@link ContactKey} objects containing the contact key
-     * information, or an empty list if no keys are found.
+     * @return a list of {@link E2eeContactKey} objects containing the end-to-end encryption
+     * contact key information, or an empty list if no keys are found.
      */
     @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
     @NonNull
-    public List<ContactKey> getOwnerContactKeys(@NonNull String lookupKey) {
+    public List<E2eeContactKey> getOwnerE2eeContactKeys(@NonNull String lookupKey) {
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.GET_OWNER_CONTACT_KEYS_METHOD, extras);
+                E2eeContactKeys.GET_OWNER_CONTACT_KEYS_METHOD, extras);
 
         if (response == null) {
             return new ArrayList<>();
         }
-        List<ContactKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS,
-                ContactKey.class);
+        List<E2eeContactKey> value = response.getParcelableArrayList(
+                E2eeContactKeys.KEY_CONTACT_KEYS, E2eeContactKey.class);
         if (value == null) {
             return new ArrayList<>();
         }
@@ -220,53 +223,51 @@
     }
 
     /**
-     * Updates a contact key entry's local verification state that belongs to the caller app.
+     * Updates an end-to-end encryption contact key entry's local verification state that belongs
+     * to the caller app.
      *
-     * @param lookupKey the value that references the contact
-     * @param deviceId an app-specified identifier for the device
-     * @param accountId an app-specified identifier for the account
+     * @param lookupKey              the value that references the contact
+     * @param deviceId               an app-specified identifier for the device
+     * @param accountId              an app-specified identifier for the account
      * @param localVerificationState the new local verification state
-     *
      * @return true if the entry was updated, false otherwise.
      */
     @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
-    public boolean updateContactKeyLocalVerificationState(@NonNull String lookupKey,
+    public boolean updateE2eeContactKeyLocalVerificationState(@NonNull String lookupKey,
             @NonNull String deviceId,
             @NonNull String accountId,
             @VerificationState int localVerificationState) {
         validateVerificationState(localVerificationState);
 
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
-        extras.putInt(ContactKeys.LOCAL_VERIFICATION_STATE, localVerificationState);
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putInt(E2eeContactKeys.LOCAL_VERIFICATION_STATE, localVerificationState);
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD, extras);
+                E2eeContactKeys.UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
     /**
-     * Updates a contact key entry's local verification state that belongs to the app identified
-     * by ownerPackageName.
+     * Updates an end-to-end encryption contact key entry's local verification state that belongs
+     * to the app identified by ownerPackageName.
      *
-     * @param lookupKey the value that references the contact
-     * @param deviceId an app-specified identifier for the device
-     * @param accountId an app-specified identifier for the account
-     * @param ownerPackageName the package name of the app that owns the key
+     * @param lookupKey              the value that references the contact
+     * @param deviceId               an app-specified identifier for the device
+     * @param accountId              an app-specified identifier for the account
+     * @param ownerPackageName       the package name of the app that owns the key
      * @param localVerificationState the new local verification state
-     *
      * @return true if the entry was updated, false otherwise.
-     *
      * @hide
      */
     @SystemApi
     @RequiresPermission(allOf = {
             android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS,
             android.Manifest.permission.WRITE_CONTACTS})
-    public boolean updateContactKeyLocalVerificationState(@NonNull String lookupKey,
+    public boolean updateE2eeContactKeyLocalVerificationState(@NonNull String lookupKey,
             @NonNull String deviceId,
             @NonNull String accountId,
             @NonNull String ownerPackageName,
@@ -274,66 +275,65 @@
         validateVerificationState(localVerificationState);
 
         final Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
-        extras.putString(ContactKeys.OWNER_PACKAGE_NAME, Objects.requireNonNull(ownerPackageName));
-        extras.putInt(ContactKeys.LOCAL_VERIFICATION_STATE, localVerificationState);
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putString(E2eeContactKeys.OWNER_PACKAGE_NAME,
+                Objects.requireNonNull(ownerPackageName));
+        extras.putInt(E2eeContactKeys.LOCAL_VERIFICATION_STATE, localVerificationState);
 
         final Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD, extras);
+                E2eeContactKeys.UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
     /**
-     * Updates a contact key entry's remote verification state that belongs to the caller app.
+     * Updates an end-to-end encryption contact key entry's remote verification state that belongs
+     * to the caller app.
      *
-     * @param lookupKey the value that references the contact
-     * @param deviceId an app-specified identifier for the device
-     * @param accountId an app-specified identifier for the account
+     * @param lookupKey               the value that references the contact
+     * @param deviceId                an app-specified identifier for the device
+     * @param accountId               an app-specified identifier for the account
      * @param remoteVerificationState the new remote verification state
-     *
      * @return true if the entry was updated, false otherwise.
      */
     @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
-    public boolean updateContactKeyRemoteVerificationState(@NonNull String lookupKey,
+    public boolean updateE2eeContactKeyRemoteVerificationState(@NonNull String lookupKey,
             @NonNull String deviceId,
             @NonNull String accountId,
             @VerificationState int remoteVerificationState) {
         validateVerificationState(remoteVerificationState);
 
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
-        extras.putInt(ContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putInt(E2eeContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
+                E2eeContactKeys.UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
     /**
-     * Updates a contact key entry's remote verification state that belongs to the app identified
-     * by ownerPackageName.
+     * Updates an end-to-end encryption contact key entry's remote verification state that belongs
+     * to the app identified by ownerPackageName.
      *
-     * @param lookupKey the value that references the contact
-     * @param deviceId an app-specified identifier for the device
-     * @param accountId an app-specified identifier for the account
-     * @param ownerPackageName the package name of the app that owns the key
+     * @param lookupKey               the value that references the contact
+     * @param deviceId                an app-specified identifier for the device
+     * @param accountId               an app-specified identifier for the account
+     * @param ownerPackageName        the package name of the app that owns the key
      * @param remoteVerificationState the new remote verification state
-     *
      * @return true if the entry was updated, false otherwise.
-     *
      * @hide
      */
     @SystemApi
     @RequiresPermission(allOf = {
             android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS,
             android.Manifest.permission.WRITE_CONTACTS})
-    public boolean updateContactKeyRemoteVerificationState(@NonNull String lookupKey,
+    public boolean updateE2eeContactKeyRemoteVerificationState(@NonNull String lookupKey,
             @NonNull String deviceId,
             @NonNull String accountId,
             @NonNull String ownerPackageName,
@@ -341,19 +341,19 @@
         validateVerificationState(remoteVerificationState);
 
         final Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
-        extras.putString(ContactKeys.OWNER_PACKAGE_NAME, Objects.requireNonNull(ownerPackageName));
-        extras.putInt(ContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putString(E2eeContactKeys.OWNER_PACKAGE_NAME,
+                Objects.requireNonNull(ownerPackageName));
+        extras.putInt(E2eeContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
 
         final Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
+                E2eeContactKeys.UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
-
     private static void validateVerificationState(int verificationState) {
         if (verificationState != VERIFICATION_STATE_UNVERIFIED
                 && verificationState != VERIFICATION_STATE_VERIFICATION_FAILED
@@ -364,53 +364,52 @@
     }
 
     /**
-     * Removes a contact key entry that belongs to the caller app.
+     * Removes an end-to-end encryption contact key entry that belongs to the caller app.
      *
      * @param lookupKey the value that references the contact
-     * @param deviceId an app-specified identifier for the device
+     * @param deviceId  an app-specified identifier for the device
      * @param accountId an app-specified identifier for the account
-     *
      * @return true if the entry was removed, false otherwise.
      */
     @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
-    public boolean removeContactKey(@NonNull String lookupKey,
+    public boolean removeE2eeContactKey(@NonNull String lookupKey,
             @NonNull String deviceId,
             @NonNull String accountId) {
         final Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
 
         final Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.REMOVE_CONTACT_KEY_METHOD, extras);
+                E2eeContactKeys.REMOVE_CONTACT_KEY_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
     /**
-     * Inserts a new entry into the self keys table or updates one if it already exists.
-
-     * @param deviceId an app-specified identifier for the device
-     * @param accountId an app-specified identifier for the account
-     * @param keyValue the raw bytes for the key (max size is {@link #getMaxKeySizeBytes} bytes)
+     * Inserts a new entry into the end-to-end encryption self keys table or updates one if it
+     * already exists.
      *
+     * @param deviceId  an app-specified identifier for the device
+     * @param accountId an app-specified identifier for the account
+     * @param keyValue  the raw bytes for the key (max size is {@link #getMaxKeySizeBytes} bytes)
      * @return true if the entry was added or updated, false otherwise.
      */
     @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
-    public boolean updateOrInsertSelfKey(@NonNull String deviceId,
+    public boolean updateOrInsertE2eeSelfKey(@NonNull String deviceId,
             @NonNull String accountId,
             @NonNull byte[] keyValue) {
         validateKeyLength(keyValue);
 
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
-        extras.putByteArray(ContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putByteArray(E2eeContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue));
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.UPDATE_OR_INSERT_SELF_KEY_METHOD, extras);
+                E2eeContactKeys.UPDATE_OR_INSERT_SELF_KEY_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
     private static void validateKeyLength(byte[] keyValue) {
@@ -422,119 +421,117 @@
     }
 
     /**
-     * Updates a self key entry's remote verification state.
+     * Updates an end-to-end encryption self key entry's remote verification state.
      *
-     * @param deviceId an app-specified identifier for the device
-     * @param accountId an app-specified identifier for the account
+     * @param deviceId                an app-specified identifier for the device
+     * @param accountId               an app-specified identifier for the account
      * @param remoteVerificationState the new remote verification state
-     *
      * @return true if the entry was updated, false otherwise.
      */
     @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
-    public boolean updateSelfKeyRemoteVerificationState(@NonNull String deviceId,
+    public boolean updateE2eeSelfKeyRemoteVerificationState(@NonNull String deviceId,
             @NonNull String accountId,
             @VerificationState int remoteVerificationState) {
         validateVerificationState(remoteVerificationState);
 
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
-        extras.putInt(ContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putInt(E2eeContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
+                E2eeContactKeys.UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
     /**
-     * Updates a self key entry's remote verification state that belongs to the app identified
-     * by ownerPackageName.
+     * Updates an end-to-end encryption self key entry's remote verification state that belongs to
+     * the app identified by ownerPackageName.
      *
-     * @param deviceId an app-specified identifier for the device
-     * @param accountId an app-specified identifier for the account
-     * @param ownerPackageName the package name of the app that owns the key
+     * @param deviceId                an app-specified identifier for the device
+     * @param accountId               an app-specified identifier for the account
+     * @param ownerPackageName        the package name of the app that owns the key
      * @param remoteVerificationState the new remote verification state
-     *
      * @return true if the entry was updated, false otherwise.
-     *
      * @hide
      */
     @SystemApi
     @RequiresPermission(allOf = {
             android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS,
             android.Manifest.permission.WRITE_CONTACTS})
-    public boolean updateSelfKeyRemoteVerificationState(@NonNull String deviceId,
+    public boolean updateE2eeSelfKeyRemoteVerificationState(@NonNull String deviceId,
             @NonNull String accountId,
             @NonNull String ownerPackageName,
             @VerificationState int remoteVerificationState) {
         validateVerificationState(remoteVerificationState);
 
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
-        extras.putString(ContactKeys.OWNER_PACKAGE_NAME, Objects.requireNonNull(ownerPackageName));
-        extras.putInt(ContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putString(E2eeContactKeys.OWNER_PACKAGE_NAME,
+                Objects.requireNonNull(ownerPackageName));
+        extras.putInt(E2eeContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
+                E2eeContactKeys.UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
     /**
-     * Maximum size of a contact key.
+     * Maximum size of an end-to-end encryption contact key.
      */
     public static int getMaxKeySizeBytes() {
         return MAX_KEY_SIZE_BYTES;
     }
 
     /**
-     * Returns a self key entry given the deviceId and the inferred package name of the caller.
+     * Returns an end-to-end encryption self key entry given the deviceId and the inferred package
+     * name of the caller.
      *
-     * @param deviceId an app-specified identifier for the device
+     * @param deviceId  an app-specified identifier for the device
      * @param accountId an app-specified identifier for the account
-     *
-     * @return a {@link SelfKey} object containing the self key information, or null if no self key
-     * is found.
+     * @return a {@link E2eeSelfKey} object containing the end-to-end encryption self key
+     * information, or null if no self key is found.
      */
     @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
     @Nullable
-    public SelfKey getSelfKey(@NonNull String deviceId,
+    public E2eeSelfKey getE2eeSelfKey(@NonNull String deviceId,
             @NonNull String accountId) {
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.GET_SELF_KEY_METHOD, extras);
+                E2eeContactKeys.GET_SELF_KEY_METHOD, extras);
 
         if (response == null) {
             return null;
         }
-        return response.getParcelable(ContactKeys.KEY_CONTACT_KEY, SelfKey.class);
+        return response.getParcelable(E2eeContactKeys.KEY_CONTACT_KEY, E2eeSelfKey.class);
     }
 
     /**
-     * Returns all self key entries that belong to apps visible to the caller.
+     * Returns all end-to-end encryption self key entries that belong to apps visible to the caller.
      * The keys will be stripped of deviceId, timeUpdated and keyValue data.
      *
-     * @return a list of {@link SelfKey} objects containing the self key information, or
-     * an empty list if no keys are found.
+     * @return a list of {@link E2eeSelfKey} objects containing the end-to-end encryption self key
+     * information, or an empty list if no self keys are found.
      */
     @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
     @NonNull
-    public List<SelfKey> getAllSelfKeys() {
+    public List<E2eeSelfKey> getAllE2eeSelfKeys() {
         Bundle extras = new Bundle();
 
-        Bundle response = nullSafeCall(mContentResolver, ContactKeys.GET_ALL_SELF_KEYS_METHOD,
+        Bundle response = nullSafeCall(mContentResolver, E2eeContactKeys.GET_ALL_SELF_KEYS_METHOD,
                 extras);
 
         if (response == null) {
             return new ArrayList<>();
         }
-        List<SelfKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS,
-                SelfKey.class);
+        List<E2eeSelfKey> value = response.getParcelableArrayList(E2eeContactKeys.KEY_CONTACT_KEYS,
+                E2eeSelfKey.class);
         if (value == null) {
             return new ArrayList<>();
         }
@@ -542,24 +539,24 @@
     }
 
     /**
-     * Returns all self key entries that are owned by the caller app.
+     * Returns all end-to-end encryption self key entries that are owned by the caller app.
      *
-     * @return a list of {@link SelfKey} objects containing the self key information, or
-     * an empty list if no keys are found.
+     * @return a list of {@link E2eeSelfKey} objects containing the end-to-end encryption self key
+     * information, or an empty list if no self keys are found.
      */
     @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
     @NonNull
-    public List<SelfKey> getOwnerSelfKeys() {
+    public List<E2eeSelfKey> getOwnerE2eeSelfKeys() {
         Bundle extras = new Bundle();
 
-        Bundle response = nullSafeCall(mContentResolver, ContactKeys.GET_OWNER_SELF_KEYS_METHOD,
+        Bundle response = nullSafeCall(mContentResolver, E2eeContactKeys.GET_OWNER_SELF_KEYS_METHOD,
                 extras);
 
         if (response == null) {
             return new ArrayList<>();
         }
-        List<SelfKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS,
-                SelfKey.class);
+        List<E2eeSelfKey> value = response.getParcelableArrayList(E2eeContactKeys.KEY_CONTACT_KEYS,
+                E2eeSelfKey.class);
         if (value == null) {
             return new ArrayList<>();
         }
@@ -567,24 +564,24 @@
     }
 
     /**
-     * Removes a self key entry given the deviceId and the inferred package name of the caller.
-
-     * @param deviceId an app-specified identifier for the device
+     * Removes an end-to-end encryption self key entry given the deviceId and the inferred
+     * package name of the caller.
+     *
+     * @param deviceId  an app-specified identifier for the device
      * @param accountId an app-specified identifier for the account
-     *
      * @return true if the entry was removed, false otherwise.
      */
     @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
-    public boolean removeSelfKey(@NonNull String deviceId,
+    public boolean removeE2eeSelfKey(@NonNull String deviceId,
             @NonNull String accountId) {
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.REMOVE_SELF_KEY_METHOD, extras);
+                E2eeContactKeys.REMOVE_SELF_KEY_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
     private Bundle nullSafeCall(@NonNull ContentResolver resolver, @NonNull String method,
@@ -598,6 +595,7 @@
 
     /**
      * Possible values of verification state.
+     *
      * @hide
      */
     @IntDef(prefix = {"VERIFICATION_STATE_"}, value = {
@@ -606,7 +604,8 @@
             VERIFICATION_STATE_VERIFIED
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface VerificationState {}
+    public @interface VerificationState {
+    }
 
     /**
      * Unverified state of a contact end to end encrypted key.
@@ -622,9 +621,10 @@
     public static final int VERIFICATION_STATE_VERIFIED = 2;
 
     /** @hide */
-    public static final class ContactKeys {
+    public static final class E2eeContactKeys {
 
-        private ContactKeys() {}
+        private E2eeContactKeys() {
+        }
 
         /**
          * <p>
@@ -636,14 +636,16 @@
 
         /**
          * <p>
-         * An app-specified identifier for the device for which the contact key can be used.
+         * An app-specified identifier for the device for which the end-to-end encryption
+         * contact key can be used.
          * </p>
          */
         public static final String DEVICE_ID = "device_id";
 
         /**
          * <p>
-         * An app-specified identifier for the account for which the contact key can be used.
+         * An app-specified identifier for the account for which the end-to-end encryption
+         * contact key can be used.
          * Usually a phone number.
          * </p>
          */
@@ -718,29 +720,32 @@
         public static final String GET_CONTACT_KEY_METHOD = "getContactKey";
 
         /**
-         * The method to invoke in order to retrieve all contact keys.
+         * The method to invoke in order to retrieve all end-to-end encryption contact keys.
          */
         public static final String GET_ALL_CONTACT_KEYS_METHOD = "getAllContactKeys";
 
         /**
-         * The method to invoke in order to retrieve contact keys that belong to the caller.
+         * The method to invoke in order to retrieve end-to-end encryption contact keys that belong
+         * to the caller.
          */
         public static final String GET_OWNER_CONTACT_KEYS_METHOD = "getOwnerContactKeys";
 
         /**
-         * The method to invoke in order to update a contact key local verification state.
+         * The method to invoke in order to update an end-to-end encryption contact key local
+         * verification state.
          */
         public static final String UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD =
                 "updateContactKeyLocalVerificationState";
 
         /**
-         * The method to invoke in order to update a contact key remote verification state.
+         * The method to invoke in order to update an end-to-end encryption contact key remote
+         * verification state.
          */
         public static final String UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD =
                 "updateContactKeyRemoteVerificationState";
 
         /**
-         * The method to invoke in order to remove a contact key.
+         * The method to invoke in order to remove a end-to-end encryption contact key.
          */
         public static final String REMOVE_CONTACT_KEY_METHOD = "removeContactKey";
 
@@ -776,12 +781,12 @@
         public static final String REMOVE_SELF_KEY_METHOD = "removeSelfKey";
 
         /**
-         * Key in the incoming Bundle for all the contact keys.
+         * Key in the incoming Bundle for all the end-to-end encryption contact keys.
          */
         public static final String KEY_CONTACT_KEYS = "key_contact_keys";
 
         /**
-         * Key in the incoming Bundle for a single contact key.
+         * Key in the incoming Bundle for a single end-to-end encryption contact key.
          */
         public static final String KEY_CONTACT_KEY = "key_contact_key";
 
@@ -790,36 +795,10 @@
          */
         public static final String KEY_UPDATED_ROWS = "key_updated_rows";
     }
-
     /**
      * A parcelable class encapsulating other users' end to end encrypted contact key.
      */
-    public static final class ContactKey implements Parcelable {
-        /**
-         * An app-specified identifier for the device for which the contact key can be used.
-         */
-        private final String mDeviceId;
-
-        /**
-         * An app-specified identifier for the account for which the contact key can be used.
-         * Usually a phone number.
-         */
-        private final String mAccountId;
-
-        /**
-         * Owner application package name.
-         */
-        private final String mOwnerPackageName;
-
-        /**
-         * Timestamp at which the key was updated.
-         */
-        private final long mTimeUpdated;
-
-        /**
-         * The raw bytes for the key.
-         */
-        private final byte[] mKeyValue;
+    public static final class E2eeContactKey extends E2eeBaseKey implements Parcelable {
 
         /**
          * Describes the local verification state for the key, for instance QR-code based
@@ -828,12 +807,6 @@
         private final int mLocalVerificationState;
 
         /**
-         * Describes the remote verification state for the key, for instance through a key
-         * transparency server.
-         */
-        private final int mRemoteVerificationState;
-
-        /**
          * The display name for the contact.
          */
         private final String mDisplayName;
@@ -851,79 +824,21 @@
         /**
          * @hide
          */
-        public ContactKey(@Nullable String deviceId, @NonNull String accountId,
+        public E2eeContactKey(@Nullable String deviceId, @NonNull String accountId,
                 @NonNull String ownerPackageName, long timeUpdated, @Nullable byte[] keyValue,
                 @VerificationState int localVerificationState,
                 @VerificationState int remoteVerificationState,
                 @Nullable String displayName,
                 @Nullable String phoneNumber, @Nullable String emailAddress) {
-            this.mDeviceId = deviceId;
-            this.mAccountId = accountId;
-            this.mOwnerPackageName = ownerPackageName;
-            this.mTimeUpdated = timeUpdated;
-            this.mKeyValue = keyValue == null ? null : Arrays.copyOf(keyValue, keyValue.length);
+            super(deviceId, accountId, ownerPackageName, timeUpdated, keyValue,
+                    remoteVerificationState);
             this.mLocalVerificationState = localVerificationState;
-            this.mRemoteVerificationState = remoteVerificationState;
             this.mDisplayName = displayName;
             this.mPhoneNumber = phoneNumber;
             this.mEmailAddress = emailAddress;
         }
 
         /**
-         * Gets the app-specified identifier for the device for which the contact key can be used.
-         * Returns null if the app doesn't have the required visibility into the contact key.
-         *
-         * @return An app-specified identifier for the device.
-         */
-        @Nullable
-        public String getDeviceId() {
-            return mDeviceId;
-        }
-
-        /**
-         * Gets the app-specified identifier for the account for which the contact key can be used.
-         * Usually a phone number.
-         *
-         * @return An app-specified identifier for the account.
-         */
-        @NonNull
-        public String getAccountId() {
-            return mAccountId;
-        }
-
-        /**
-         * Gets the owner application package name.
-         *
-         * @return The owner application package name.
-         */
-        @NonNull
-        public String getOwnerPackageName() {
-            return mOwnerPackageName;
-        }
-
-        /**
-         * Gets the timestamp at which the key was updated. Returns -1 if the app doesn't have the
-         * required visibility into the contact key.
-         *
-         * @return The timestamp at which the key was updated in the System.currentTimeMillis()
-         * base.
-         */
-        public long getTimeUpdated() {
-            return mTimeUpdated;
-        }
-
-        /**
-         * Gets the raw bytes for the key.
-         * Returns null if the app doesn't have the required visibility into the contact key.
-         *
-         * @return A copy of the raw bytes for the key.
-         */
-        @Nullable
-        public byte[] getKeyValue() {
-            return mKeyValue == null ? null : Arrays.copyOf(mKeyValue, mKeyValue.length);
-        }
-
-        /**
          * Gets the local verification state for the key, for instance QR-code based verification.
          *
          * @return The local verification state for the key.
@@ -933,16 +848,6 @@
         }
 
         /**
-         * Gets the remote verification state for the key, for instance through a key transparency
-         * server.
-         *
-         * @return The remote verification state for the key.
-         */
-        public @VerificationState int getRemoteVerificationState() {
-            return mRemoteVerificationState;
-        }
-
-        /**
          * Gets the display name for the contact.
          *
          * @return The display name for the contact.
@@ -984,7 +889,7 @@
             if (obj == null) return false;
             if (obj == this) return true;
 
-            if (!(obj instanceof ContactKey toCompare)) {
+            if (!(obj instanceof E2eeContactKey toCompare)) {
                 return false;
             }
 
@@ -1023,10 +928,10 @@
         }
 
         @NonNull
-        public static final Creator<ContactKey> CREATOR =
+        public static final Creator<E2eeContactKey> CREATOR =
                 new Creator<>() {
                     @Override
-                    public ContactKey createFromParcel(Parcel source) {
+                    public E2eeContactKey createFromParcel(Parcel source) {
                         String deviceId = source.readString8();
                         String accountId = source.readString8();
                         String ownerPackageName = source.readString8();
@@ -1044,14 +949,14 @@
                         String displayName = source.readString8();
                         String number = source.readString8();
                         String address = source.readString8();
-                        return new ContactKey(deviceId, accountId, ownerPackageName,
+                        return new E2eeContactKey(deviceId, accountId, ownerPackageName,
                                 timeUpdated, keyValue, localVerificationState,
                                 remoteVerificationState, displayName, number, address);
                     }
 
                     @Override
-                    public ContactKey[] newArray(int size) {
-                        return new ContactKey[size];
+                    public E2eeContactKey[] newArray(int size) {
+                        return new E2eeContactKey[size];
                     }
                 };
     }
@@ -1059,116 +964,15 @@
     /**
      * A parcelable class encapsulating self end to end encrypted contact key.
      */
-    public static final class SelfKey implements Parcelable {
-        /**
-         * An app-specified identifier for the device for which the contact key can be used.
-         */
-        private final String mDeviceId;
-
-        /**
-         * An app-specified identifier for the account for which the contact key can be used.
-         * Usually a phone number.
-         */
-        private final String mAccountId;
-
-        /**
-         * Owner application package name.
-         */
-        private final String mOwnerPackageName;
-
-        /**
-         * Timestamp at which the key was updated.
-         */
-        private final long mTimeUpdated;
-
-        /**
-         * The raw bytes for the key.
-         */
-        private final byte[] mKeyValue;
-
-
-        /**
-         * Describes the remote verification state for the key, for instance through a key
-         * transparency server.
-         */
-        private final int mRemoteVerificationState;
-
+    public static final class E2eeSelfKey extends E2eeBaseKey implements Parcelable {
         /**
          * @hide
          */
-        public SelfKey(@Nullable String deviceId, @NonNull String accountId,
+        public E2eeSelfKey(@Nullable String deviceId, @NonNull String accountId,
                 @NonNull String ownerPackageName, long timeUpdated, @Nullable byte[] keyValue,
                 @VerificationState int remoteVerificationState) {
-            this.mDeviceId = deviceId;
-            this.mAccountId = accountId;
-            this.mOwnerPackageName = ownerPackageName;
-            this.mTimeUpdated = timeUpdated;
-            this.mKeyValue = keyValue == null ? null : Arrays.copyOf(keyValue, keyValue.length);
-            this.mRemoteVerificationState = remoteVerificationState;
-        }
-
-        /**
-         * Gets the app-specified identifier for the device for which the contact key can be used.
-         * Returns null if the app doesn't have the required visibility into the contact key.
-         *
-         * @return An app-specified identifier for the device.
-         */
-        @Nullable
-        public String getDeviceId() {
-            return mDeviceId;
-        }
-
-        /**
-         * Gets the app-specified identifier for the account for which the contact key can be used.
-         * Usually a phone number.
-         *
-         * @return An app-specified identifier for the device.
-         */
-        @NonNull
-        public String getAccountId() {
-            return mAccountId;
-        }
-
-        /**
-         * Gets the owner application package name.
-         *
-         * @return The owner application package name.
-         */
-        @NonNull
-        public String getOwnerPackageName() {
-            return mOwnerPackageName;
-        }
-
-        /**
-         * Gets the timestamp at which the key was updated. Returns -1 if the app doesn't have the
-         * required visibility into the contact key.
-         *
-         * @return The timestamp at which the key was updated in the System.currentTimeMillis()
-         * base.
-         */
-        public long getTimeUpdated() {
-            return mTimeUpdated;
-        }
-
-        /**
-         * Gets the raw bytes for the key.
-         * Returns null if the app doesn't have the required visibility into the contact key.
-         *
-         * @return A copy of the raw bytes for the key.
-         */
-        @Nullable
-        public byte[] getKeyValue() {
-            return mKeyValue == null ? null : Arrays.copyOf(mKeyValue, mKeyValue.length);
-        }
-
-        /**
-         * Gets the remote verification state for the key, for instance through a key transparency
-         * server.
-         *
-         * @return The remote verification state for the key.
-         */
-        public @VerificationState int getRemoteVerificationState() {
-            return mRemoteVerificationState;
+            super(deviceId, accountId, ownerPackageName, timeUpdated, keyValue,
+                    remoteVerificationState);
         }
 
         @Override
@@ -1182,7 +986,7 @@
             if (obj == null) return false;
             if (obj == this) return true;
 
-            if (!(obj instanceof SelfKey toCompare)) {
+            if (!(obj instanceof E2eeSelfKey toCompare)) {
                 return false;
             }
 
@@ -1213,10 +1017,10 @@
         }
 
         @NonNull
-        public static final Creator<SelfKey> CREATOR =
+        public static final Creator<E2eeSelfKey> CREATOR =
                 new Creator<>() {
                     @Override
-                    public SelfKey createFromParcel(Parcel source) {
+                    public E2eeSelfKey createFromParcel(Parcel source) {
                         String deviceId = source.readString8();
                         String accountId = source.readString8();
                         String ownerPackageName = source.readString8();
@@ -1230,14 +1034,132 @@
                             keyValue = null;
                         }
                         int remoteVerificationState = source.readInt();
-                        return new SelfKey(deviceId, accountId, ownerPackageName,
+                        return new E2eeSelfKey(deviceId, accountId, ownerPackageName,
                                 timeUpdated, keyValue, remoteVerificationState);
                     }
 
                     @Override
-                    public SelfKey[] newArray(int size) {
-                        return new SelfKey[size];
+                    public E2eeSelfKey[] newArray(int size) {
+                        return new E2eeSelfKey[size];
                     }
                 };
     }
+
+    /**
+     * An abstract class that's extended by self and contact key classes.
+     *
+     * @hide
+     */
+    abstract static class E2eeBaseKey {
+        /**
+         * An app-specified identifier for the device for which the key can be used.
+         */
+        protected final String mDeviceId;
+
+        /**
+         * An app-specified identifier for the account for which the key can be used.
+         * Usually a phone number.
+         */
+        protected final String mAccountId;
+
+        /**
+         * Owner application package name.
+         */
+        protected final String mOwnerPackageName;
+
+        /**
+         * Timestamp at which the key was updated.
+         */
+        protected final long mTimeUpdated;
+
+        /**
+         * The raw bytes for the key.
+         */
+        protected final byte[] mKeyValue;
+
+        /**
+         * Describes the remote verification state for the end-to-end encryption key, for instance
+         * through a key transparency server.
+         */
+        protected final int mRemoteVerificationState;
+
+        protected E2eeBaseKey(@Nullable String deviceId, @NonNull String accountId,
+                @NonNull String ownerPackageName, long timeUpdated, @Nullable byte[] keyValue,
+                @VerificationState int remoteVerificationState) {
+            this.mDeviceId = deviceId;
+            this.mAccountId = accountId;
+            this.mOwnerPackageName = ownerPackageName;
+            this.mTimeUpdated = timeUpdated;
+            this.mKeyValue = keyValue == null ? null : Arrays.copyOf(keyValue, keyValue.length);
+            this.mRemoteVerificationState = remoteVerificationState;
+        }
+
+        /**
+         * Gets the app-specified identifier for the device for which the end-to-end encryption
+         * key can be used.
+         * Returns null if the app doesn't have the required visibility into
+         * the end-to-end encryption key.
+         *
+         * @return An app-specified identifier for the device.
+         */
+        @Nullable
+        public String getDeviceId() {
+            return mDeviceId;
+        }
+
+        /**
+         * Gets the app-specified identifier for the account for which the end-to-end encryption
+         * key can be used.
+         * Usually a phone number.
+         *
+         * @return An app-specified identifier for the account.
+         */
+        @NonNull
+        public String getAccountId() {
+            return mAccountId;
+        }
+
+        /**
+         * Gets the owner application package name.
+         *
+         * @return The owner application package name.
+         */
+        @NonNull
+        public String getOwnerPackageName() {
+            return mOwnerPackageName;
+        }
+
+        /**
+         * Gets the timestamp at which the end-to-end encryption key was updated. Returns -1 if
+         * the app doesn't have the required visibility into the key.
+         *
+         * @return The timestamp at which the key was updated in the System.currentTimeMillis()
+         * base.
+         */
+        public long getTimeUpdated() {
+            return mTimeUpdated;
+        }
+
+        /**
+         * Gets the raw bytes for the end-to-end encryption key.
+         * Returns null if the app doesn't have the required visibility into
+         * the end-to-end encryption key.
+         *
+         * @return A copy of the raw bytes for the end-to-end encryption key.
+         */
+        @Nullable
+        public byte[] getKeyValue() {
+            return mKeyValue == null ? null : Arrays.copyOf(mKeyValue, mKeyValue.length);
+        }
+
+        /**
+         * Gets the remote verification state for the end-to-end encryption key, for instance
+         * through a key transparency server.
+         *
+         * @return The remote verification state for the end-to-end encryption key.
+         */
+        public @VerificationState int getRemoteVerificationState() {
+            return mRemoteVerificationState;
+        }
+    }
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 50adc40..eea6464 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -471,6 +471,21 @@
             "android.settings.ACCESSIBILITY_COLOR_MOTION_SETTINGS";
 
     /**
+     * Activity Action: Show settings to allow configuration of accessibility color contrast.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_ACCESSIBILITY_COLOR_CONTRAST_SETTINGS =
+            "android.settings.ACCESSIBILITY_COLOR_CONTRAST_SETTINGS";
+
+    /**
      * Activity Action: Show settings to allow configuration of Reduce Bright Colors.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -11561,6 +11576,15 @@
                 "extra_low_power_warning_acknowledged";
 
         /**
+         * Whether the emergency thermal alert would be disabled
+         * (0: default) or not (1).
+         *
+         * @hide
+         */
+        public static final String EMERGENCY_THERMAL_ALERT_DISABLED =
+                "emergency_thermal_alert_disabled";
+
+        /**
          * 0 (default) Auto battery saver suggestion has not been suppressed. 1) it has been
          * suppressed.
          * @hide
@@ -11969,6 +11993,16 @@
                 "accessibility_pinch_to_zoom_anywhere_enabled";
 
         /**
+         * For magnification feature where panning can be controlled with a single finger.
+         *
+         * If true, you can pan using a single finger gesture.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED =
+                "accessibility_single_finger_panning_enabled";
+
+        /**
          * Controls magnification capability. Accessibility magnification is capable of at least one
          * of the magnification modes.
          *
diff --git a/core/java/android/security/ConfirmationPrompt.java b/core/java/android/security/ConfirmationPrompt.java
index d8c44ad..f626149 100644
--- a/core/java/android/security/ConfirmationPrompt.java
+++ b/core/java/android/security/ConfirmationPrompt.java
@@ -92,7 +92,6 @@
     private Executor mExecutor;
     private Context mContext;
 
-    private final KeyStore mKeyStore = KeyStore.getInstance();
     private AndroidProtectedConfirmation mProtectedConfirmation;
 
     private AndroidProtectedConfirmation getService() {
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index 7631454..5e7edda 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -31,6 +31,13 @@
 }
 
 flag {
+    name: "keyinfo_unlocked_device_required"
+    namespace: "hardware_backed_security"
+    description: "Add the API android.security.keystore.KeyInfo#isUnlockedDeviceRequired()"
+    bug: "296475382"
+}
+
+flag {
     name: "deprecate_fsv_sig"
     namespace: "hardware_backed_security"
     description: "Feature flag for deprecating .fsv_sig"
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index f1054ec..c171c1b 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -26,7 +26,6 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
-import android.security.KeyStore;
 import android.security.KeyStore2;
 import android.security.keystore.KeyPermanentlyInvalidatedException;
 import android.security.keystore2.AndroidKeyStoreProvider;
@@ -272,11 +271,9 @@
     public static final int ERROR_KEY_NOT_FOUND = 30;
 
     private final ILockSettings mBinder;
-    private final KeyStore mKeyStore;
 
-    private RecoveryController(ILockSettings binder, KeyStore keystore) {
+    private RecoveryController(ILockSettings binder) {
         mBinder = binder;
-        mKeyStore = keystore;
     }
 
     /**
@@ -296,7 +293,7 @@
         // lockSettings may be null.
         ILockSettings lockSettings =
                 ILockSettings.Stub.asInterface(ServiceManager.getService("lock_settings"));
-        return new RecoveryController(lockSettings, KeyStore.getInstance());
+        return new RecoveryController(lockSettings);
     }
 
     /**
diff --git a/core/java/android/service/chooser/flags.aconfig b/core/java/android/service/chooser/flags.aconfig
index 00236df..d72441f 100644
--- a/core/java/android/service/chooser/flags.aconfig
+++ b/core/java/android/service/chooser/flags.aconfig
@@ -27,3 +27,14 @@
   description: "Provides additional callbacks with information about user actions in ChooserResult"
   bug: "263474465"
 }
+
+flag {
+  name: "legacy_chooser_pinning_removal"
+  namespace: "intentresolver"
+  description: "Removing pinning functionality from the legacy chooser (used by partial screenshare)"
+  bug: "301068735"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 264b53c..d821074 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -174,6 +174,23 @@
         return sbnKey;
     }
 
+    /**
+     * @return Whether the Entry is a group child by the app or system
+     * @hide
+     */
+    public boolean isAppOrSystemGroupChild() {
+        return isGroup() && !getNotification().isGroupSummary();
+    }
+
+
+    /**
+     * @return Whether the Entry is a group summary by the app or system
+     * @hide
+     */
+    public boolean isAppOrSystemGroupSummary() {
+        return isGroup() && getNotification().isGroupSummary();
+    }
+
     private String groupKey() {
         if (overrideGroupKey != null) {
             return user.getIdentifier() + "|" + pkg + "|" + "g:" + overrideGroupKey;
diff --git a/core/java/android/service/ondeviceintelligence/IOnDeviceIntelligenceService.aidl b/core/java/android/service/ondeviceintelligence/IOnDeviceIntelligenceService.aidl
index bbb4bc6..e44c69c 100644
--- a/core/java/android/service/ondeviceintelligence/IOnDeviceIntelligenceService.aidl
+++ b/core/java/android/service/ondeviceintelligence/IOnDeviceIntelligenceService.aidl
@@ -26,6 +26,7 @@
 import android.app.ondeviceintelligence.IListFeaturesCallback;
 import android.app.ondeviceintelligence.IFeatureDetailsCallback;
 import com.android.internal.infra.AndroidFuture;
+import android.service.ondeviceintelligence.IRemoteProcessingService;
 
 
 /**
@@ -41,4 +42,5 @@
     void getReadOnlyFileDescriptor(in String fileName, in AndroidFuture<ParcelFileDescriptor> future);
     void getReadOnlyFeatureFileDescriptorMap(in Feature feature, in RemoteCallback remoteCallback);
     void requestFeatureDownload(in Feature feature, in ICancellationSignal cancellationSignal, in IDownloadCallback downloadCallback);
+    void registerRemoteServices(in IRemoteProcessingService remoteProcessingService);
 }
\ No newline at end of file
diff --git a/core/java/android/service/ondeviceintelligence/IOnDeviceTrustedInferenceService.aidl b/core/java/android/service/ondeviceintelligence/IOnDeviceTrustedInferenceService.aidl
index 08eb927..e3fda04 100644
--- a/core/java/android/service/ondeviceintelligence/IOnDeviceTrustedInferenceService.aidl
+++ b/core/java/android/service/ondeviceintelligence/IOnDeviceTrustedInferenceService.aidl
@@ -23,8 +23,10 @@
 import android.app.ondeviceintelligence.Content;
 import android.app.ondeviceintelligence.Feature;
 import android.os.ICancellationSignal;
+import android.os.PersistableBundle;
+import android.os.Bundle;
 import android.service.ondeviceintelligence.IRemoteStorageService;
-
+import android.service.ondeviceintelligence.IProcessingUpdateStatusCallback;
 
 /**
  * Interface for a concrete implementation to provide on device trusted inference.
@@ -41,4 +43,6 @@
     void processRequestStreaming(in Feature feature, in Content request, in int requestType,
                                 in ICancellationSignal cancellationSignal, in IProcessingSignal processingSignal,
                                 in IStreamingResponseCallback callback);
+    void updateProcessingState(in Bundle processingState,
+                                     in IProcessingUpdateStatusCallback callback);
 }
\ No newline at end of file
diff --git a/core/java/android/service/ondeviceintelligence/IProcessingUpdateStatusCallback.aidl b/core/java/android/service/ondeviceintelligence/IProcessingUpdateStatusCallback.aidl
new file mode 100644
index 0000000..7ead869
--- /dev/null
+++ b/core/java/android/service/ondeviceintelligence/IProcessingUpdateStatusCallback.aidl
@@ -0,0 +1,14 @@
+package android.service.ondeviceintelligence;
+
+import android.os.PersistableBundle;
+
+/**
+  * Interface for receiving status from a updateProcessingState call from on-device intelligence
+  * service.
+  *
+  * @hide
+  */
+interface IProcessingUpdateStatusCallback {
+    void onSuccess(in PersistableBundle statusParams) = 1;
+    void onFailure(int errorCode, in String errorMessage) = 2;
+}
diff --git a/core/java/android/service/ondeviceintelligence/IRemoteProcessingService.aidl b/core/java/android/service/ondeviceintelligence/IRemoteProcessingService.aidl
new file mode 100644
index 0000000..32a8a6a
--- /dev/null
+++ b/core/java/android/service/ondeviceintelligence/IRemoteProcessingService.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.ondeviceintelligence;
+
+import android.os.Bundle;
+import android.service.ondeviceintelligence.IProcessingUpdateStatusCallback;
+
+
+/**
+ * Interface for a concrete implementation to provide methods to update state of a remote service.
+ *
+ * @hide
+ */
+oneway interface IRemoteProcessingService {
+    void updateProcessingState(in Bundle processingState,
+                                 in IProcessingUpdateStatusCallback callback);
+}
diff --git a/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java b/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java
index 0cba1d3..46ba25d 100644
--- a/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java
+++ b/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java
@@ -18,6 +18,7 @@
 
 import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -47,11 +48,18 @@
 
 import com.android.internal.infra.AndroidFuture;
 
+import androidx.annotation.IntDef;
+
 import java.io.File;
 import java.io.FileNotFoundException;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 import java.util.function.LongConsumer;
 
@@ -64,6 +72,10 @@
  * {@code config_defaultOnDeviceIntelligenceService}. If this config has no value, a stub is
  * returned.
  *
+ * <p> Similar to {@link OnDeviceIntelligenceManager} class, the contracts in this service are
+ * defined to be open-ended in general, to allow interoperability. Therefore, it is recommended
+ * that implementations of this system-service expose this API to the clients via a library which
+ * has more defined contract.</p>
  * <pre>
  * {@literal
  * <service android:name=".SampleOnDeviceIntelligenceService"
@@ -78,6 +90,8 @@
 public abstract class OnDeviceIntelligenceService extends Service {
     private static final String TAG = OnDeviceIntelligenceService.class.getSimpleName();
 
+    private volatile IRemoteProcessingService mRemoteProcessingService;
+
     /**
      * The {@link Intent} that must be declared as handled by the service. To be supported, the
      * service must also require the
@@ -88,6 +102,7 @@
     public static final String SERVICE_INTERFACE =
             "android.service.ondeviceintelligence.OnDeviceIntelligenceService";
 
+
     /**
      * @hide
      */
@@ -167,12 +182,58 @@
                                 remoteCallback.sendResult(bundle);
                             });
                 }
+
+                @Override
+                public void registerRemoteServices(
+                        IRemoteProcessingService remoteProcessingService) {
+                    mRemoteProcessingService = remoteProcessingService;
+                }
             };
         }
         Slog.w(TAG, "Incorrect service interface, returning null.");
         return null;
     }
 
+    /**
+     * Invoked by the {@link OnDeviceIntelligenceService} inorder to send updates to the inference
+     * service if there is a state change to be performed.
+     *
+     * @param processingState  the updated state to be applied.
+     * @param callbackExecutor executor to the run status callback on.
+     * @param statusReceiver   receiver to get status of the update state operation.
+     */
+    public final void updateProcessingState(@NonNull Bundle processingState,
+            @NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull OutcomeReceiver<PersistableBundle, OnDeviceUpdateProcessingException> statusReceiver) {
+        Objects.requireNonNull(callbackExecutor);
+        if (mRemoteProcessingService == null) {
+            throw new IllegalStateException("Remote processing service is unavailable.");
+        }
+        try {
+            mRemoteProcessingService.updateProcessingState(processingState,
+                    new IProcessingUpdateStatusCallback.Stub() {
+                        @Override
+                        public void onSuccess(PersistableBundle result) {
+                            Binder.withCleanCallingIdentity(() -> {
+                                callbackExecutor.execute(
+                                        () -> statusReceiver.onResult(result));
+                            });
+                        }
+
+                        @Override
+                        public void onFailure(int errorCode, String errorMessage) {
+                            Binder.withCleanCallingIdentity(() -> callbackExecutor.execute(
+                                    () -> statusReceiver.onError(
+                                            new OnDeviceUpdateProcessingException(
+                                                    errorCode, errorMessage))));
+                        }
+                    });
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Error in updateProcessingState: " + e);
+            throw new RuntimeException(e);
+        }
+    }
+
     private OutcomeReceiver<Feature,
             OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerException> wrapFeatureCallback(
             IFeatureCallback featureCallback) {
@@ -197,7 +258,6 @@
                 }
             }
         };
-
     }
 
     private OutcomeReceiver<List<Feature>,
@@ -380,4 +440,60 @@
      * @param versionConsumer consumer to populate the version.
      */
     public abstract void onGetVersion(@NonNull LongConsumer versionConsumer);
+
+
+    /**
+     * Exception type to be populated when calls to {@link #updateProcessingState} fail.
+     */
+    public static class OnDeviceUpdateProcessingException extends
+            OnDeviceIntelligenceServiceException {
+        /**
+         * The connection to remote service failed and the processing state could not be updated.
+         */
+        public static final int PROCESSING_UPDATE_STATUS_CONNECTION_FAILED = 1;
+
+
+        /**
+         * @hide
+         */
+        @IntDef(value = {
+                PROCESSING_UPDATE_STATUS_CONNECTION_FAILED
+        }, open = true)
+        @Target({ElementType.TYPE_USE, ElementType.METHOD, ElementType.PARAMETER,
+                ElementType.FIELD})
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface ErrorCode {
+        }
+
+        public OnDeviceUpdateProcessingException(@ErrorCode int errorCode) {
+            super(errorCode);
+        }
+
+        public OnDeviceUpdateProcessingException(@ErrorCode int errorCode,
+                @NonNull String errorMessage) {
+            super(errorCode, errorMessage);
+        }
+    }
+
+    /**
+     * Exception type to be used for surfacing errors to service implementation.
+     */
+    public abstract static class OnDeviceIntelligenceServiceException extends Exception {
+        private final int mErrorCode;
+
+        public OnDeviceIntelligenceServiceException(int errorCode) {
+            this.mErrorCode = errorCode;
+        }
+
+        public OnDeviceIntelligenceServiceException(int errorCode,
+                @NonNull String errorMessage) {
+            super(errorMessage);
+            this.mErrorCode = errorCode;
+        }
+
+        public int getErrorCode() {
+            return mErrorCode;
+        }
+
+    }
 }
diff --git a/core/java/android/service/ondeviceintelligence/OnDeviceTrustedInferenceService.java b/core/java/android/service/ondeviceintelligence/OnDeviceTrustedInferenceService.java
index 96982e3..8600197 100644
--- a/core/java/android/service/ondeviceintelligence/OnDeviceTrustedInferenceService.java
+++ b/core/java/android/service/ondeviceintelligence/OnDeviceTrustedInferenceService.java
@@ -36,13 +36,16 @@
 import android.app.ondeviceintelligence.StreamingResponseReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.IBinder;
 import android.os.ICancellationSignal;
 import android.os.OutcomeReceiver;
 import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
+import android.service.ondeviceintelligence.OnDeviceIntelligenceService.OnDeviceUpdateProcessingException;
 import android.util.Log;
 import android.util.Slog;
 
@@ -65,6 +68,11 @@
  * non-streaming fashion. Also, provides a way to register a storage service that will be used to
  * read-only access files from the {@link OnDeviceIntelligenceService} counterpart. </p>
  *
+ * <p> Similar to {@link OnDeviceIntelligenceManager} class, the contracts in this service are
+ * defined to be open-ended in general, to allow interoperability. Therefore, it is recommended
+ * that implementations of this system-service expose this API to the clients via a library which
+ * has more defined contract.</p>
+ *
  * <pre>
  * {@literal
  * <service android:name=".SampleTrustedInferenceService"
@@ -152,6 +160,17 @@
                             wrapResponseCallback(callback)
                     );
                 }
+
+                @Override
+                public void updateProcessingState(Bundle processingState,
+                        IProcessingUpdateStatusCallback callback) {
+                    Objects.requireNonNull(processingState);
+                    Objects.requireNonNull(callback);
+
+                    OnDeviceTrustedInferenceService.this.onUpdateProcessingState(processingState,
+                            wrapOutcomeReceiver(callback)
+                    );
+                }
             };
         }
         Slog.w(TAG, "Incorrect service interface, returning null.");
@@ -233,6 +252,21 @@
             @NonNull OutcomeReceiver<Content,
                     OnDeviceIntelligenceManager.OnDeviceIntelligenceManagerProcessingException> callback);
 
+
+    /**
+     * Invoked when processing environment needs to be updated or refreshed with fresh
+     * configuration, files or state.
+     *
+     * @param processingState contains updated state and params that are to be applied to the
+     *                        processing environmment,
+     * @param callback        callback to populate the update status and if there are params
+     *                        associated with the status.
+     */
+    public abstract void onUpdateProcessingState(@NonNull Bundle processingState,
+            @NonNull OutcomeReceiver<PersistableBundle,
+                    OnDeviceUpdateProcessingException> callback);
+
+
     /**
      * Overrides {@link Context#openFileInput} to read files with the given file names under the
      * internal app storage of the {@link OnDeviceIntelligenceService}, i.e., only files stored in
@@ -407,4 +441,31 @@
             }
         };
     }
+
+    @NonNull
+    private static OutcomeReceiver<PersistableBundle, OnDeviceUpdateProcessingException> wrapOutcomeReceiver(
+            IProcessingUpdateStatusCallback callback) {
+        return new OutcomeReceiver<>() {
+            @Override
+            public void onResult(@NonNull PersistableBundle result) {
+                try {
+                    callback.onSuccess(result);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending result: " + e);
+
+                }
+            }
+
+            @Override
+            public void onError(
+                    @androidx.annotation.NonNull OnDeviceUpdateProcessingException error) {
+                try {
+                    callback.onFailure(error.getErrorCode(), error.getMessage());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error sending exception details: " + e);
+                }
+            }
+        };
+    }
+
 }
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 20adc54..306410c 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -519,7 +519,7 @@
             @NonNull String keyphrase, @SuppressLint("UseIcu") @NonNull Locale locale,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull AlwaysOnHotwordDetector.Callback callback) {
-        // TODO(b/269080850): Resolve AndroidFrameworkRequiresPermission lint warning
+        // TODO (b/269080850): Resolve AndroidFrameworkRequiresPermission lint warning
 
         Objects.requireNonNull(keyphrase);
         Objects.requireNonNull(locale);
@@ -545,10 +545,6 @@
             @NonNull SoundTrigger.ModuleProperties moduleProperties,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull AlwaysOnHotwordDetector.Callback callback) {
-        // TODO(b/305787465): Remove the MANAGE_HOTWORD_DETECTION permission enforcement on the
-        // {@link #createAlwaysOnHotwordDetectorForTest(String, Locale,
-        // SoundTrigger.ModuleProperties, AlwaysOnHotwordDetector.Callback)} and replace with the
-        // permission RECEIVE_SANDBOX_TRIGGER_AUDIO when it is fully launched.
 
         Objects.requireNonNull(keyphrase);
         Objects.requireNonNull(locale);
@@ -615,11 +611,6 @@
             @Nullable PersistableBundle options,
             @Nullable SharedMemory sharedMemory,
             @SuppressLint("MissingNullability") AlwaysOnHotwordDetector.Callback callback) {
-        // TODO(b/305787465): Remove the MANAGE_HOTWORD_DETECTION permission enforcement on the
-        // {@link #createAlwaysOnHotwordDetector(String, Locale, PersistableBundle, SharedMemory,
-        // AlwaysOnHotwordDetector.Callback)} and replace with the permission
-        // RECEIVE_SANDBOX_TRIGGER_AUDIO when it is fully launched.
-
         return createAlwaysOnHotwordDetectorInternal(keyphrase, locale,
                 /* supportHotwordDetectionService= */ true, options, sharedMemory,
                 /* modulProperties */ null, /* executor= */ null, callback);
@@ -671,11 +662,7 @@
             @Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull AlwaysOnHotwordDetector.Callback callback) {
-        // TODO(b/269080850): Resolve AndroidFrameworkRequiresPermission lint warning
-        // TODO(b/305787465): Remove the MANAGE_HOTWORD_DETECTION permission enforcement on the
-        // {@link #createAlwaysOnHotwordDetector(String, Locale, PersistableBundle, SharedMemory,
-        // Executor, AlwaysOnHotwordDetector.Callback)} and replace with the permission
-        // RECEIVE_SANDBOX_TRIGGER_AUDIO when it is fully launched.
+        // TODO (b/269080850): Resolve AndroidFrameworkRequiresPermission lint warning
 
         Objects.requireNonNull(keyphrase);
         Objects.requireNonNull(locale);
@@ -702,10 +689,6 @@
             @NonNull SoundTrigger.ModuleProperties moduleProperties,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull AlwaysOnHotwordDetector.Callback callback) {
-        // TODO(b/305787465): Remove the MANAGE_HOTWORD_DETECTION permission enforcement on the
-        // {@link #createAlwaysOnHotwordDetectorForTest(String, Locale, PersistableBundle,
-        // SharedMemory, SoundTrigger.ModuleProperties, Executor, AlwaysOnHotwordDetector.Callback)}
-        // and replace with the permission RECEIVE_SANDBOX_TRIGGER_AUDIO when it is fully launched.
 
         Objects.requireNonNull(keyphrase);
         Objects.requireNonNull(locale);
diff --git a/core/java/android/tracing/flags.aconfig b/core/java/android/tracing/flags.aconfig
index b1bca96..cedba85 100644
--- a/core/java/android/tracing/flags.aconfig
+++ b/core/java/android/tracing/flags.aconfig
@@ -8,7 +8,7 @@
 }
 
 flag {
-    name: "perfetto_protolog"
+    name: "perfetto_protolog_tracing"
     namespace: "windowing_tools"
     description: "Migrate protolog to Perfetto"
     bug: "276432490"
diff --git a/core/java/android/tracing/perfetto/DataSource.java b/core/java/android/tracing/perfetto/DataSource.java
index 4e08aee..d0c719b 100644
--- a/core/java/android/tracing/perfetto/DataSource.java
+++ b/core/java/android/tracing/perfetto/DataSource.java
@@ -18,6 +18,8 @@
 
 import android.util.proto.ProtoInputStream;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 /**
  * Templated base class meant to be derived by embedders to create a custom data
  * source.
@@ -87,7 +89,8 @@
      *
      * NOTE: Should only be called from native side.
      */
-    protected TlsStateType createTlsState(CreateTlsStateArgs<DataSourceInstanceType> args) {
+    @VisibleForTesting
+    public TlsStateType createTlsState(CreateTlsStateArgs<DataSourceInstanceType> args) {
         return null;
     }
 
diff --git a/core/java/android/tracing/perfetto/DataSourceInstance.java b/core/java/android/tracing/perfetto/DataSourceInstance.java
index 3710b4d..904cf55 100644
--- a/core/java/android/tracing/perfetto/DataSourceInstance.java
+++ b/core/java/android/tracing/perfetto/DataSourceInstance.java
@@ -16,6 +16,8 @@
 
 package android.tracing.perfetto;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 /**
  * @hide
  */
@@ -66,7 +68,8 @@
      * Only required to be called when instance was retrieved with
      * `DataSource#getDataSourceInstanceLocked`.
      */
-    public final void release() {
+    @VisibleForTesting
+    public void release() {
         mDataSource.releaseDataSourceInstance(mInstanceIndex);
     }
 
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index b33214d..8358b9a 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -72,8 +72,11 @@
  * a positive value may be considered as a successful invocation.
  */
 @android.ravenwood.annotation.RavenwoodKeepWholeClass
-@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
-        "com.android.platform.test.ravenwood.nativesubstitution.Log_host")
+@android.ravenwood.annotation.RavenwoodClassLoadHook(
+        "com.android.platform.test.ravenwood.runtimehelper.ClassLoadHook.onClassLoaded")
+// Uncomment the following annotation to switch to the Java substitution version.
+//@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
+//        "com.android.platform.test.ravenwood.nativesubstitution.Log_host")
 public final class Log {
     /** @hide */
     @IntDef({ASSERT, ERROR, WARN, INFO, DEBUG, VERBOSE})
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index 00657ea..66655fc 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -188,8 +188,7 @@
                 // check whether the stylus we are tracking goes up.
                 if (mState != null) {
                     mState.mShouldInitHandwriting = false;
-                    if (!mState.mHasInitiatedHandwriting
-                            && !mState.mHasPreparedHandwritingDelegation) {
+                    if (!mState.mHandled) {
                         // The user just did a click, long click or another stylus gesture,
                         // show hover icon again for the connected view.
                         mShowHoverIconForConnectedView = true;
@@ -204,16 +203,14 @@
                 // Either we've already tried to initiate handwriting, or the ongoing MotionEvent
                 // sequence is considered to be tap, long-click or other gestures.
                 if (!mState.mShouldInitHandwriting || mState.mExceedHandwritingSlop) {
-                    return mState.mHasInitiatedHandwriting
-                            || mState.mHasPreparedHandwritingDelegation;
+                    return mState.mHandled;
                 }
 
                 final long timeElapsed =
                         motionEvent.getEventTime() - mState.mStylusDownTimeInMillis;
                 if (timeElapsed > mHandwritingTimeoutInMillis) {
                     mState.mShouldInitHandwriting = false;
-                    return mState.mHasInitiatedHandwriting
-                            || mState.mHasPreparedHandwritingDelegation;
+                    return mState.mHandled;
                 }
 
                 final int pointerIndex = motionEvent.findPointerIndex(mState.mStylusPointerId);
@@ -223,7 +220,7 @@
                     mState.mExceedHandwritingSlop = true;
                     View candidateView = findBestCandidateView(mState.mStylusDownX,
                             mState.mStylusDownY, /* isHover */ false);
-                    if (candidateView != null) {
+                    if (candidateView != null && candidateView.isEnabled()) {
                         if (candidateView == getConnectedOrFocusedView()) {
                             if (!mInitiateWithoutConnection && !candidateView.hasFocus()) {
                                 requestFocusWithoutReveal(candidateView);
@@ -246,7 +243,7 @@
                         }
                     }
                 }
-                return mState.mHasInitiatedHandwriting || mState.mHasPreparedHandwritingDelegation;
+                return mState.mHandled;
         }
         return false;
     }
@@ -382,7 +379,7 @@
     @VisibleForTesting
     public void startHandwriting(@NonNull View view) {
         mImm.startStylusHandwriting(view);
-        mState.mHasInitiatedHandwriting = true;
+        mState.mHandled = true;
         mState.mShouldInitHandwriting = false;
         mShowHoverIconForConnectedView = false;
         if (view instanceof TextView) {
@@ -402,13 +399,12 @@
             mImm.startConnectionlessStylusHandwritingForDelegation(
                     view, getCursorAnchorInfoForConnectionless(view), delegatePackageName,
                     view::post, new DelegationCallback(view, delegatePackageName));
-            mState.mHasInitiatedHandwriting = true;
             mState.mShouldInitHandwriting = false;
         } else {
             mImm.prepareStylusHandwritingDelegation(view, delegatePackageName);
             view.getHandwritingDelegatorCallback().run();
-            mState.mHasPreparedHandwritingDelegation = true;
         }
+        mState.mHandled = true;
     }
 
     /**
@@ -455,7 +451,7 @@
 
     private void onDelegationAccepted(View view) {
         if (mState != null) {
-            mState.mHasInitiatedHandwriting = true;
+            mState.mHandled = true;
             mState.mShouldInitHandwriting = false;
         }
         if (view instanceof TextView) {
@@ -795,12 +791,12 @@
          * This boolean will be set to false, and it won't request to start handwriting.
          */
         private boolean mShouldInitHandwriting;
-        /**
-         * Whether handwriting mode has already been initiated for the current MotionEvent sequence.
-         */
-        private boolean mHasInitiatedHandwriting;
 
-        private boolean mHasPreparedHandwritingDelegation;
+        /**
+         * Whether the current MotionEvent sequence has been handled by the handwriting initiator,
+         * either by initiating handwriting mode, or by preparing handwriting delegation.
+         */
+        private boolean mHandled;
 
         /**
          * Whether the current ongoing stylus MotionEvent sequence already exceeds the
@@ -838,8 +834,7 @@
             mStylusDownY = motionEvent.getY(actionIndex);
 
             mShouldInitHandwriting = true;
-            mHasInitiatedHandwriting = false;
-            mHasPreparedHandwritingDelegation = false;
+            mHandled = false;
             mExceedHandwritingSlop = false;
         }
     }
@@ -1052,8 +1047,6 @@
                     // Fall back to the old delegation flow
                     mImm.prepareStylusHandwritingDelegation(mView, mDelegatePackageName);
                     mView.getHandwritingDelegatorCallback().run();
-                    mState.mHasInitiatedHandwriting = false;
-                    mState.mHasPreparedHandwritingDelegation = true;
                     break;
             }
         }
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 11180ae..5ee526e 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -73,7 +73,7 @@
      *
      * @param types internal insets types (WindowInsets.Type.InsetsType) to show
      * @param fromIme true if this request originated from IME (InputMethodService).
-     * @param statsToken the token tracking the current IME show request or {@code null} otherwise.
+     * @param statsToken the token tracking the current IME request or {@code null} otherwise.
      */
     void showInsets(int types, boolean fromIme, in @nullable ImeTracker.Token statsToken);
 
@@ -82,7 +82,7 @@
      *
      * @param types internal insets types (WindowInsets.Type.InsetsType) to hide
      * @param fromIme true if this request originated from IME (InputMethodService).
-     * @param statsToken the token tracking the current IME hide request or {@code null} otherwise.
+     * @param statsToken the token tracking the current IME request or {@code null} otherwise.
      */
     void hideInsets(int types, boolean fromIme, in @nullable ImeTracker.Token statsToken);
 
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index d68a47c..e126836 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -148,13 +148,13 @@
             int seqId);
 
     @UnsupportedAppUsage
-    boolean performHapticFeedback(int effectId, boolean always);
+    boolean performHapticFeedback(int effectId, boolean always, boolean fromIme);
 
     /**
      * Called by attached views to perform predefined haptic feedback without requiring VIBRATE
      * permission.
      */
-    oneway void performHapticFeedbackAsync(int effectId, boolean always);
+    oneway void performHapticFeedbackAsync(int effectId, boolean always, boolean fromIme);
 
     /**
      * Initiate the drag operation itself
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index de809c8..821e13d 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -21,9 +21,9 @@
 import static android.view.ImeInsetsSourceConsumerProto.INSETS_SOURCE_CONSUMER;
 import static android.view.ImeInsetsSourceConsumerProto.IS_REQUESTED_VISIBLE_AWAITING_CONTROL;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.IBinder;
-import android.os.Process;
 import android.os.Trace;
 import android.util.proto.ProtoOutputStream;
 import android.view.SurfaceControl.Transaction;
@@ -70,7 +70,11 @@
         if (!isShowRequested()) {
             mIsRequestedVisibleAwaitingControl = false;
             if (!running && !mHasPendingRequest) {
-                notifyHidden(null /* statsToken */);
+                final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+                        ImeTracker.ORIGIN_CLIENT,
+                        SoftInputShowHideReason.HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED,
+                        mController.getHost().isHandlingPointerEvent() /* fromUser */);
+                notifyHidden(statsToken);
                 removeSurface();
             }
         }
@@ -144,9 +148,17 @@
 
     void requestHide(boolean fromIme, @Nullable ImeTracker.Token statsToken) {
         if (!fromIme) {
+            // Create a new token to track the hide request when we have control,
+            // as we use the passed in token for the insets animation already.
+            final var notifyStatsToken = getControl() != null
+                    ? ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+                        ImeTracker.ORIGIN_CLIENT,
+                        SoftInputShowHideReason.HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL,
+                        mController.getHost().isHandlingPointerEvent() /* fromUser */)
+                    : statsToken;
             // The insets might be controlled by a remote target. Let the server know we are
             // requested to hide.
-            notifyHidden(statsToken);
+            notifyHidden(notifyStatsToken);
         }
         if (mAnimationState == ANIMATION_STATE_SHOW) {
             mHasPendingRequest = true;
@@ -157,21 +169,9 @@
      * Notify {@link com.android.server.inputmethod.InputMethodManagerService} that
      * IME insets are hidden.
      *
-     * @param statsToken the token tracking the current IME hide request or {@code null} otherwise.
+     * @param statsToken the token tracking the current IME request or {@code null} otherwise.
      */
-    private void notifyHidden(@Nullable ImeTracker.Token statsToken) {
-        // Create a new stats token to track the hide request when:
-        //  - we do not already have one, or
-        //  - we do already have one, but we have control and use the passed in token
-        //      for the insets animation already.
-        if (statsToken == null || getControl() != null) {
-            statsToken = ImeTracker.forLogging().onRequestHide(null /* component */,
-                    Process.myUid(),
-                    ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
-                    SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API,
-                    mController.getHost().isHandlingPointerEvent() /* fromUser */);
-        }
-
+    private void notifyHidden(@NonNull ImeTracker.Token statsToken) {
         ImeTracker.forLogging().onProgress(statsToken,
                 ImeTracker.PHASE_CLIENT_INSETS_CONSUMER_NOTIFY_HIDDEN);
 
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 7f1e037..85c779b 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -43,7 +43,6 @@
 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;
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
 
@@ -165,9 +164,9 @@
         mStatsToken = statsToken;
         if (DEBUG_IME_VISIBILITY && (types & ime()) != 0) {
             EventLog.writeEvent(IMF_IME_ANIM_START,
-                    mStatsToken != null ? mStatsToken.getTag() : TOKEN_NONE, mAnimationType,
-                    mCurrentAlpha, "Current:" + mCurrentInsets, "Shown:" + mShownInsets,
-                    "Hidden:" + mHiddenInsets);
+                    mStatsToken != null ? mStatsToken.getTag() : ImeTracker.TOKEN_NONE,
+                    mAnimationType, mCurrentAlpha, "Current:" + mCurrentInsets,
+                    "Shown:" + mShownInsets, "Hidden:" + mHiddenInsets);
         }
         mController.startAnimation(this, listener, types, mAnimation,
                 new Bounds(mHiddenInsets, mShownInsets));
@@ -245,6 +244,7 @@
     }
 
     @Override
+    @Nullable
     public ImeTracker.Token getStatsToken() {
         return mStatsToken;
     }
@@ -330,8 +330,8 @@
         mListener.onFinished(this);
         if (DEBUG_IME_VISIBILITY && (mTypes & ime()) != 0) {
             EventLog.writeEvent(IMF_IME_ANIM_FINISH,
-                    mStatsToken != null ? mStatsToken.getTag() : TOKEN_NONE, mAnimationType,
-                    mCurrentAlpha, shown ? 1 : 0, Objects.toString(insets));
+                    mStatsToken != null ? mStatsToken.getTag() : ImeTracker.TOKEN_NONE,
+                    mAnimationType, mCurrentAlpha, shown ? 1 : 0, Objects.toString(insets));
         }
     }
 
@@ -355,8 +355,8 @@
         if (DEBUG) Log.d(TAG, "notify Control request cancelled for types: " + mTypes);
         if (DEBUG_IME_VISIBILITY && (mTypes & ime()) != 0) {
             EventLog.writeEvent(IMF_IME_ANIM_CANCEL,
-                    mStatsToken != null ? mStatsToken.getTag() : TOKEN_NONE, mAnimationType,
-                    Objects.toString(mPendingInsets));
+                    mStatsToken != null ? mStatsToken.getTag() : ImeTracker.TOKEN_NONE,
+                    mAnimationType, Objects.toString(mPendingInsets));
         }
         releaseLeashes();
     }
diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java
index 079991a..92e20e0 100644
--- a/core/java/android/view/InsetsAnimationThreadControlRunner.java
+++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java
@@ -137,6 +137,7 @@
     }
 
     @Override
+    @Nullable
     public ImeTracker.Token getStatsToken() {
         return mControl.getStatsToken();
     }
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 1803a6e..6cc4b20 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -28,7 +28,6 @@
 import static android.view.WindowInsets.Type.all;
 import static android.view.WindowInsets.Type.captionBar;
 import static android.view.WindowInsets.Type.ime;
-import static android.view.inputmethod.ImeTracker.PHASE_CLIENT_ANIMATION_CANCEL;
 
 import android.animation.AnimationHandler;
 import android.animation.Animator;
@@ -47,7 +46,6 @@
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Process;
 import android.os.Trace;
 import android.text.TextUtils;
 import android.util.IntArray;
@@ -659,6 +657,7 @@
     private final Runnable mAnimCallback;
 
     /** Pending control request that is waiting on IME to be ready to be shown */
+    @Nullable
     private PendingControlRequest mPendingImeControlRequest;
 
     private int mWindowType;
@@ -1043,12 +1042,18 @@
         hideTypes[0] &= ~animatingTypes;
 
         if (showTypes[0] != 0) {
-            applyAnimation(showTypes[0], true /* show */, false /* fromIme */,
-                    null /* statsToken */);
+            final var statsToken = (showTypes[0] & ime()) == 0 ? null
+                    : ImeTracker.forLogging().onStart(ImeTracker.TYPE_SHOW,
+                            ImeTracker.ORIGIN_CLIENT, SoftInputShowHideReason.CONTROLS_CHANGED,
+                            mHost.isHandlingPointerEvent() /* fromUser */);
+            applyAnimation(showTypes[0], true /* show */, false /* fromIme */, statsToken);
         }
         if (hideTypes[0] != 0) {
-            applyAnimation(hideTypes[0], false /* show */, false /* fromIme */,
-                    null /* statsToken */);
+            final var statsToken = (hideTypes[0] & ime()) == 0 ? null
+                    : ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+                            ImeTracker.ORIGIN_CLIENT, SoftInputShowHideReason.CONTROLS_CHANGED,
+                            mHost.isHandlingPointerEvent() /* fromUser */);
+            applyAnimation(hideTypes[0], false /* show */, false /* fromIme */, statsToken);
         }
 
         if (mControllableTypes != controllableTypes) {
@@ -1064,15 +1069,7 @@
 
     @Override
     public void show(@InsetsType int types) {
-        ImeTracker.Token statsToken = null;
-        if ((types & ime()) != 0) {
-            statsToken = ImeTracker.forLogging().onRequestShow(null /* component */,
-                    Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
-                    SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API,
-                    mHost.isHandlingPointerEvent() /* fromUser */);
-        }
-
-        show(types, false /* fromIme */, statsToken);
+        show(types, false /* fromIme */, null /* statsToken */);
     }
 
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
@@ -1080,6 +1077,13 @@
             @Nullable ImeTracker.Token statsToken) {
         if ((types & ime()) != 0) {
             Log.d(TAG, "show(ime(), fromIme=" + fromIme + ")");
+
+            if (statsToken == null) {
+                statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_SHOW,
+                        ImeTracker.ORIGIN_CLIENT,
+                        SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API,
+                        mHost.isHandlingPointerEvent() /* fromUser */);
+            }
         }
         if (fromIme) {
             ImeTracing.getInstance().triggerClientDump("InsetsController#show",
@@ -1148,9 +1152,11 @@
     }
 
     /**
-     * Handle the {@link #mPendingImeControlRequest} when
-     * - The IME insets is ready to show.
-     * - The IME insets has being requested invisible.
+     * Handle the {@link #mPendingImeControlRequest} when:
+     * <ul>
+     *     <li> The IME insets is ready to show.
+     *     <li> The IME insets has being requested invisible.
+     * </ul>
      */
     private void handlePendingControlRequest(@Nullable ImeTracker.Token statsToken) {
         PendingControlRequest pendingRequest = mPendingImeControlRequest;
@@ -1170,20 +1176,22 @@
 
     @Override
     public void hide(@InsetsType int types) {
-        ImeTracker.Token statsToken = null;
-        if ((types & ime()) != 0) {
-            statsToken = ImeTracker.forLogging().onRequestHide(null /* component */,
-                    Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
-                    SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API,
-                    mHost.isHandlingPointerEvent() /* fromUser */);
-        }
-
-        hide(types, false /* fromIme */, statsToken);
+        hide(types, false /* fromIme */, null /* statsToken */);
     }
 
     @VisibleForTesting
     public void hide(@InsetsType int types, boolean fromIme,
             @Nullable ImeTracker.Token statsToken) {
+        if ((types & ime()) != 0) {
+            Log.d(TAG, "hide(ime(), fromIme=" + fromIme + ")");
+
+            if (statsToken == null) {
+                statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+                        ImeTracker.ORIGIN_CLIENT,
+                        SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API,
+                        mHost.isHandlingPointerEvent() /* fromUser */);
+            }
+        }
         if (fromIme) {
             ImeTracing.getInstance().triggerClientDump("InsetsController#hide",
                     mHost.getInputMethodManager(), null /* icProto */);
@@ -1307,10 +1315,12 @@
             if (monitoredAnimation && (types & Type.ime()) != 0) {
                 if (animationType == ANIMATION_TYPE_SHOW) {
                     ImeTracker.forLatency().onShowCancelled(statsToken,
-                            PHASE_CLIENT_ANIMATION_CANCEL, ActivityThread::currentApplication);
+                            ImeTracker.PHASE_CLIENT_ANIMATION_CANCEL,
+                            ActivityThread::currentApplication);
                 } else {
                     ImeTracker.forLatency().onHideCancelled(statsToken,
-                            PHASE_CLIENT_ANIMATION_CANCEL, ActivityThread::currentApplication);
+                            ImeTracker.PHASE_CLIENT_ANIMATION_CANCEL,
+                            ActivityThread::currentApplication);
                 }
                 ImeTracker.forLogging().onCancelled(statsToken,
                         ImeTracker.PHASE_CLIENT_CONTROL_ANIMATION);
@@ -1602,12 +1612,12 @@
     private void cancelAnimation(InsetsAnimationControlRunner control, boolean invokeCallback) {
         if (invokeCallback) {
             ImeTracker.forLogging().onCancelled(control.getStatsToken(),
-                    PHASE_CLIENT_ANIMATION_CANCEL);
+                    ImeTracker.PHASE_CLIENT_ANIMATION_CANCEL);
             control.cancel();
         } else {
             // Succeeds if invokeCallback is false (i.e. when called from notifyFinished).
             ImeTracker.forLogging().onProgress(control.getStatsToken(),
-                    PHASE_CLIENT_ANIMATION_CANCEL);
+                    ImeTracker.PHASE_CLIENT_ANIMATION_CANCEL);
         }
         if (DEBUG) {
             Log.d(TAG, TextUtils.formatSimple(
diff --git a/core/java/android/view/InsetsResizeAnimationRunner.java b/core/java/android/view/InsetsResizeAnimationRunner.java
index bffaeea..ebdddd5 100644
--- a/core/java/android/view/InsetsResizeAnimationRunner.java
+++ b/core/java/android/view/InsetsResizeAnimationRunner.java
@@ -29,6 +29,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
+import android.annotation.Nullable;
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.util.SparseArray;
@@ -92,6 +93,7 @@
     }
 
     @Override
+    @Nullable
     public ImeTracker.Token getStatsToken() {
         // Return null as resizing the IME view is not explicitly tracked.
         return null;
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 0ce61bb..fdb2a6e 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -314,7 +314,7 @@
      * @param fromController {@code true} if request is coming from controller.
      *                       (e.g. in IME case, controller is
      *                       {@link android.inputmethodservice.InputMethodService}).
-     * @param statsToken the token tracking the current IME show request or {@code null} otherwise.
+     * @param statsToken the token tracking the current IME request or {@code null} otherwise.
      *
      * @implNote The {@code statsToken} is ignored here, and only handled in
      * {@link ImeInsetsSourceConsumer} for IME animations only.
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index ad326e4..a2f767d 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -102,6 +102,7 @@
 per-file IWindow*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
 per-file RemoteAnimation*.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file RemoteAnimation*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
+per-file ScreenRecordingCallbacks.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file *SurfaceControl*.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file SurfaceControl*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
 per-file SurfaceSession.java = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 13b9c45..9099f98 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -428,13 +428,11 @@
 
     private BitmapDrawable getBitmapDrawableFromVectorDrawable(Resources resources,
             VectorDrawable vectorDrawable) {
-        Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
-                vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
-        // BitmapDrawables and Bitmap have a default density of DisplayMetrics.DENSITY_DEVICE,
-        // (which is deprecated in favor of DENSITY_DEVICE_STABLE/resources.densityDpi). In
-        // rare cases when device density differs from the resource density, the bitmap will
-        // scale as the BitmapDrawable is created. Avoid by explicitly setting density here.
-        bitmap.setDensity(resources.getDisplayMetrics().densityDpi);
+        // Ensure we pass the display metrics into the Bitmap constructor so that it is initialized
+        // with the correct density.
+        Bitmap bitmap = Bitmap.createBitmap(resources.getDisplayMetrics(),
+                vectorDrawable.getIntrinsicWidth(),
+                vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888, true /* hasAlpha */);
         Canvas canvas = new Canvas(bitmap);
         vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
         vectorDrawable.draw(canvas);
@@ -480,11 +478,19 @@
                 mBitmapFrames = new Bitmap[frames - 1];
                 final int width = drawable.getIntrinsicWidth();
                 final int height = drawable.getIntrinsicHeight();
+                final boolean isVectorAnimation = drawable instanceof VectorDrawable;
+                mDrawNativeDropShadow = isVectorAnimation;
                 for (int i = 1; i < frames; ++i) {
                     Drawable drawableFrame = animationDrawable.getFrame(i);
-                    if (!(drawableFrame instanceof BitmapDrawable)) {
+                    if (!(drawableFrame instanceof BitmapDrawable)
+                            && !(drawableFrame instanceof VectorDrawable)) {
                         throw new IllegalArgumentException("Frame of an animated pointer icon "
-                                + "must refer to a bitmap drawable.");
+                                + "must refer to a bitmap drawable or vector drawable.");
+                    }
+                    if (isVectorAnimation != (drawableFrame instanceof VectorDrawable)) {
+                        throw new IllegalArgumentException("The drawable of the " + i + "-th frame "
+                                + "is a different type from the others. All frames should be the "
+                                + "same type.");
                     }
                     if (drawableFrame.getIntrinsicWidth() != width ||
                         drawableFrame.getIntrinsicHeight() != height) {
@@ -492,8 +498,11 @@
                                 + "is different. All frames should have the exact same size and "
                                 + "share the same hotspot.");
                     }
-                    BitmapDrawable bitmapDrawableFrame = (BitmapDrawable) drawableFrame;
-                    mBitmapFrames[i - 1] = getBitmapFromDrawable(bitmapDrawableFrame);
+                    if (isVectorAnimation) {
+                        drawableFrame = getBitmapDrawableFromVectorDrawable(resources,
+                                (VectorDrawable) drawableFrame);
+                    }
+                    mBitmapFrames[i - 1] = getBitmapFromDrawable((BitmapDrawable) drawableFrame);
                 }
             }
         }
diff --git a/core/java/android/view/RoundedCorners.java b/core/java/android/view/RoundedCorners.java
index f68cc69..1f841bf 100644
--- a/core/java/android/view/RoundedCorners.java
+++ b/core/java/android/view/RoundedCorners.java
@@ -198,6 +198,12 @@
             radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius);
         }
         array.recycle();
+        // For devices with round displays (e.g. watches) that don't otherwise provide the rounded
+        // corner radius via resource overlays, we can infer the corner radius directly from the
+        // display size.
+        if (radius == 0 && res.getConfiguration().isScreenRound()) {
+            radius = res.getDisplayMetrics().widthPixels / 2;
+        }
         return radius;
     }
 
diff --git a/core/java/android/view/ScrollFeedbackProvider.java b/core/java/android/view/ScrollFeedbackProvider.java
index 8a44d4f..798203f 100644
--- a/core/java/android/view/ScrollFeedbackProvider.java
+++ b/core/java/android/view/ScrollFeedbackProvider.java
@@ -21,8 +21,11 @@
 import android.view.flags.Flags;
 
 /**
- * Interface to represent an entity giving consistent feedback for different events surrounding view
- * scroll.
+ * Provides feedback to the user for scroll events on a {@link View}. The type of feedback provided
+ * to the user may depend on the {@link InputDevice} that generated the scroll events.
+ *
+ * <p>An example of the type of feedback that this interface may provide is haptic feedback (that
+ * is, tactile feedback that provide the user physical feedback for their scroll).
  *
  * <p>The interface provides methods for the client to report different scroll events. The client
  * should report all scroll events that they want to be considered for scroll feedback using the
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 896b3f4..124aece 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -883,6 +885,17 @@
         mListener = listener;
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    protected int calculateFrameRateCategory(float sizePercentage) {
+        if (mMinusTwoFrameIntervalMillis > 15 && mMinusOneFrameIntervalMillis > 15) {
+            return FRAME_RATE_CATEGORY_NORMAL;
+        }
+        return super.calculateFrameRateCategory(sizePercentage);
+    }
+
     @UnsupportedAppUsage
     private final SurfaceTexture.OnFrameAvailableListener mUpdateListener =
             surfaceTexture -> {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4df95bf..828004b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -25,6 +25,7 @@
 import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
 import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE;
 import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS;
 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW;
@@ -5649,9 +5650,15 @@
 
     private int mInfrequentUpdateCount = 0;
     private long mLastUpdateTimeMillis = 0;
-    private long mMinusOneFrameIntervalMillis = 0;
-    private long mMinusTwoFrameIntervalMillis = 0;
-    private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_HIGH;
+    /**
+     * @hide
+     */
+    protected long mMinusOneFrameIntervalMillis = 0;
+    /**
+     * @hide
+     */
+    protected long mMinusTwoFrameIntervalMillis = 0;
+    private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
 
     @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
     public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = Float.NaN;
@@ -9952,6 +9959,17 @@
     }
 
     /**
+     * @hide
+     */
+    public void onGetCredentialException(String errorType, String errorMsg) {
+        if (getCredentialManagerCallback() == null) {
+            Log.w(AUTOFILL_LOG_TAG, "onGetCredentialException called but no callback found");
+            return;
+        }
+        getCredentialManagerCallback().onError(new GetCredentialException(errorType, errorMsg));
+    }
+
+    /**
      * Gets the unique, logical identifier of this view in the activity, for autofill purposes.
      *
      * <p>The autofill id is created on demand, unless it is explicitly set by
@@ -10387,7 +10405,9 @@
     }
 
     /**
-     * Sets content sensitivity mode to determine whether this view displays sensitive content.
+     * Sets content sensitivity mode to determine whether this view displays sensitive content
+     * (e.g. username, password etc.). The system may improve user privacy i.e. hide content
+     * drawn by a sensitive view from screen sharing and recording.
      *
      * @param mode {@link #CONTENT_SENSITIVITY_AUTO}, {@link #CONTENT_SENSITIVITY_NOT_SENSITIVE}
      *                                            or {@link #CONTENT_SENSITIVITY_SENSITIVE}
@@ -15297,6 +15317,7 @@
      * {@link #isLongClickable()}, {@link #isContextClickable()},
      * {@link #isScreenReaderFocusable()}, or {@link #isFocusable()}
      * <li>Has an {@link AccessibilityDelegate}
+     * <li>Has an {@link AccessibilityNodeProvider}
      * <li>Has an interaction listener, e.g. {@link OnTouchListener},
      * {@link OnKeyListener}, etc.
      * <li>Is an accessibility live region, e.g.
@@ -15329,7 +15350,8 @@
         }
 
         return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility()
-                || hasListenersForAccessibility() || mAccessibilityDelegate != null
+                || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null
+                || getAccessibilityDelegate() != null
                 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE
                 || isAccessibilityPane() || isAccessibilityHeading();
     }
@@ -16796,10 +16818,15 @@
             mAttachInfo.mViewRootImpl.getWindowVisibleDisplayFrame(outRect);
             return;
         }
-        // The view is not attached to a display so we don't have a context.
-        // Make a best guess about the display size.
-        Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
-        d.getRectSize(outRect);
+        // TODO (b/327559224): Refine the behavior to better reflect the window environment with API
+        //  doc updates.
+        final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
+        final WindowMetrics metrics = windowManager.getMaximumWindowMetrics();
+        final Insets insets = metrics.getWindowInsets().getInsets(
+                WindowInsets.Type.navigationBars() | WindowInsets.Type.displayCutout());
+        outRect.set(metrics.getBounds());
+        outRect.inset(insets);
+        outRect.offsetTo(0, 0);
     }
 
     /**
@@ -28352,15 +28379,19 @@
         }
 
         final boolean always = (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0;
+        boolean fromIme = false;
+        if (mAttachInfo.mViewRootImpl != null) {
+            fromIme = mAttachInfo.mViewRootImpl.mWindowAttributes.type == TYPE_INPUT_METHOD;
+        }
         if (Flags.useVibratorHapticFeedback()) {
             if (!mAttachInfo.canPerformHapticFeedback()) {
                 return false;
             }
             getSystemVibrator().performHapticFeedback(
-                    feedbackConstant, always, "View#performHapticFeedback");
+                    feedbackConstant, always, "View#performHapticFeedback", fromIme);
             return true;
         }
-        return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, always);
+        return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, always, fromIme);
     }
 
     private Vibrator getSystemVibrator() {
@@ -31403,7 +31434,7 @@
 
         interface Callbacks {
             void playSoundEffect(int effectId);
-            boolean performHapticFeedback(int effectId, boolean always);
+            boolean performHapticFeedback(int effectId, boolean always, boolean fromIme);
         }
 
         /**
@@ -33612,7 +33643,12 @@
         return (float) viewSize / screenSize;
     }
 
-    private int calculateFrameRateCategory(float sizePercentage) {
+    /**
+     * Used to calculate the frame rate category of a View.
+     *
+     * @hide
+     */
+    protected int calculateFrameRateCategory(float sizePercentage) {
         if (mMinusTwoFrameIntervalMillis + mMinusOneFrameIntervalMillis
                 < INFREQUENT_UPDATE_INTERVAL_MILLIS) {
             if (sizePercentage <= FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD) {
@@ -33747,6 +33783,9 @@
         mMinusOneFrameIntervalMillis = timeIntervalMillis;
 
         mLastUpdateTimeMillis = currentTimeMillis;
+        if (mMinusTwoFrameIntervalMillis >= 30 && timeIntervalMillis < 2) {
+            return;
+        }
         if (timeIntervalMillis >= INFREQUENT_UPDATE_INTERVAL_MILLIS) {
             mInfrequentUpdateCount = mInfrequentUpdateCount == INFREQUENT_UPDATE_COUNTS
                         ? mInfrequentUpdateCount : mInfrequentUpdateCount + 1;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 23a7017..a7cb169 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -95,12 +95,14 @@
 import static android.view.accessibility.Flags.fixMergedContentChangeEvent;
 import static android.view.accessibility.Flags.forceInvertColor;
 import static android.view.accessibility.Flags.reduceWindowContentChangedEventThrottle;
+import static android.view.flags.Flags.toolkitFrameRateTypingReadOnly;
 import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision;
 import static android.view.flags.Flags.toolkitSetFrameRateReadOnly;
 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
 
 import static com.android.input.flags.Flags.enablePointerChoreographer;
+import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay;
 
 import android.Manifest;
 import android.accessibilityservice.AccessibilityService;
@@ -997,8 +999,6 @@
      */
     private final boolean mViewBoundsSandboxingEnabled;
 
-    private int mLastTransformHint = Integer.MIN_VALUE;
-
     private AccessibilityWindowAttributes mAccessibilityWindowAttributes;
 
     /*
@@ -1044,7 +1044,7 @@
     // time for checking idle status periodically.
     private static final int FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS = 500;
     // time for revaluating the idle status before lowering the frame rate.
-    private static final int FRAME_RATE_IDLENESS_REEVALUATE_TIME = 500;
+    private static final int FRAME_RATE_IDLENESS_REEVALUATE_TIME = 1000;
     // time for evaluating the interval between current time and
     // the time when frame rate was set previously.
     private static final int FRAME_RATE_SETTING_REEVALUATE_TIME = 100;
@@ -1062,9 +1062,6 @@
      * the variables below are used to determine whther a dVRR feature should be enabled
      */
 
-    // Used to determine whether to suppress boost on typing
-    private boolean mShouldSuppressBoostOnTyping = false;
-
     /**
      * A temporary object used so relayoutWindow can return the latest SyncSeqId
      * system. The SyncSeqId system was designed to work without synchronous relayout
@@ -1118,10 +1115,12 @@
 
     private static boolean sToolkitSetFrameRateReadOnlyFlagValue;
     private static boolean sToolkitMetricsForFrameRateDecisionFlagValue;
+    private static boolean sToolkitFrameRateTypingReadOnlyFlagValue;
 
     static {
         sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly();
         sToolkitMetricsForFrameRateDecisionFlagValue = toolkitMetricsForFrameRateDecision();
+        sToolkitFrameRateTypingReadOnlyFlagValue = toolkitFrameRateTypingReadOnly();
     }
 
     // The latest input event from the gesture that was used to resolve the pointer icon.
@@ -1211,6 +1210,9 @@
             mSensitiveContentProtectionService =
                     ISensitiveContentProtectionManager.Stub.asInterface(
                         ServiceManager.getService(Context.SENSITIVE_CONTENT_PROTECTION_SERVICE));
+            if (mSensitiveContentProtectionService == null) {
+                Log.e(TAG, "SensitiveContentProtectionService shouldn't be null");
+            }
         } else {
             mSensitiveContentProtectionService = null;
         }
@@ -4180,6 +4182,9 @@
      */
     void notifySensitiveContentAppProtection(boolean showSensitiveContent) {
         try {
+            if (mSensitiveContentProtectionService == null) {
+                return;
+            }
             // The window would be blocked during screen share if it shows sensitive content.
             mSensitiveContentProtectionService.setSensitiveContentProtection(
                     getWindowToken(), mContext.getPackageName(), showSensitiveContent);
@@ -6541,6 +6546,7 @@
                         mHasInvalidation = false;
                         mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE,
                                 FRAME_RATE_IDLENESS_REEVALUATE_TIME);
+                        mHasIdledMessage = true;
                     }
                     break;
                 case MSG_REFRESH_POINTER_ICON:
@@ -8918,11 +8924,13 @@
 
         final int transformHint = SurfaceControl.rotationToBufferTransform(
                 (mDisplay.getInstallOrientation() + mDisplay.getRotation()) % 4);
+        final boolean transformHintChanged = transformHint != mPreviousTransformHint;
+        mPreviousTransformHint = transformHint;
+        mSurfaceControl.setTransformHint(transformHint);
 
         WindowLayout.computeSurfaceSize(mWindowAttributes, winConfig.getMaxBounds(), requestedWidth,
                 requestedHeight, mWinFrameInScreen, mPendingDragResizing, mSurfaceSize);
 
-        final boolean transformHintChanged = transformHint != mLastTransformHint;
         final boolean sizeChanged = !mLastSurfaceSize.equals(mSurfaceSize);
         final boolean surfaceControlChanged =
                 (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED) == RELAYOUT_RES_SURFACE_CHANGED;
@@ -8951,10 +8959,6 @@
             }
         }
 
-        mLastTransformHint = transformHint;
-
-        mSurfaceControl.setTransformHint(transformHint);
-
         if (mAttachInfo.mContentCaptureManager != null) {
             ContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
                     .getMainContentCaptureSession();
@@ -8968,8 +8972,7 @@
                 mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue);
             }
             mHdrRenderState.forceUpdateHdrSdrRatio();
-            if (mPreviousTransformHint != transformHint) {
-                mPreviousTransformHint = transformHint;
+            if (transformHintChanged) {
                 dispatchTransformHintChanged(transformHint);
             }
         } else {
@@ -9204,18 +9207,18 @@
      * {@inheritDoc}
      */
     @Override
-    public boolean performHapticFeedback(int effectId, boolean always) {
+    public boolean performHapticFeedback(int effectId, boolean always, boolean fromIme) {
         if ((mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
             return false;
         }
 
         try {
             if (USE_ASYNC_PERFORM_HAPTIC_FEEDBACK) {
-                mWindowSession.performHapticFeedbackAsync(effectId, always);
+                mWindowSession.performHapticFeedbackAsync(effectId, always, fromIme);
                 return true;
             } else {
                 // Original blocking binder call path.
-                return mWindowSession.performHapticFeedback(effectId, always);
+                return mWindowSession.performHapticFeedback(effectId, always, fromIme);
             }
         } catch (RemoteException e) {
             return false;
@@ -11933,6 +11936,14 @@
 
     @Override
     public @SurfaceControl.BufferTransform int getBufferTransformHint() {
+        // TODO(b/326482114) We use mPreviousTransformHint (calculated using mDisplay's rotation)
+        // instead of mSurfaceControl#getTransformHint because there's a race where SurfaceFlinger
+        // can set an incorrect transform hint for a few frames before it is aware of the updated
+        // display rotation.
+        if (enableBufferTransformHintFromDisplay()) {
+            return mPreviousTransformHint;
+        }
+
         if (mSurfaceControl.isValid()) {
             return mSurfaceControl.getTransformHint();
         } else {
@@ -12364,14 +12375,6 @@
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
         }
-
-        if (mPreferredFrameRateCategory != FRAME_RATE_CATEGORY_NO_PREFERENCE && !mHasIdledMessage) {
-            // Check where the display is idled periodically.
-            // If so, set the frame rate category to NO_PREFERENCE
-            mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE,
-                    FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS);
-            mHasIdledMessage = true;
-        }
     }
 
     private void setPreferredFrameRate(float preferredFrameRate) {
@@ -12385,7 +12388,8 @@
                 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
                     Trace.traceBegin(
                             Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRate "
-                                + preferredFrameRate);
+                                + preferredFrameRate + " compatibility "
+                                + mFrameRateCompatibility);
                 }
                 mFrameRateTransaction.setFrameRate(mSurfaceControl, preferredFrameRate,
                     mFrameRateCompatibility).applyAsyncUnsafe();
@@ -12411,7 +12415,7 @@
 
     private boolean shouldSetFrameRate() {
         // use toolkitSetFrameRate flag to gate the change
-        return mSurface.isValid() && mPreferredFrameRate > 0
+        return mSurface.isValid() && mPreferredFrameRate >= 0
                 && shouldEnableDvrr() && !mIsFrameRateConflicted;
     }
 
@@ -12419,7 +12423,8 @@
         boolean desiredAction = motionEventAction == MotionEvent.ACTION_DOWN
                 || motionEventAction == MotionEvent.ACTION_MOVE
                 || motionEventAction == MotionEvent.ACTION_UP;
-        boolean undesiredType = windowType == TYPE_INPUT_METHOD && mShouldSuppressBoostOnTyping;
+        boolean undesiredType = windowType == TYPE_INPUT_METHOD
+                && sToolkitFrameRateTypingReadOnlyFlagValue;
         // use toolkitSetFrameRate flag to gate the change
         return desiredAction && !undesiredType && shouldEnableDvrr()
                 && getFrameRateBoostOnTouchEnabled();
@@ -12452,6 +12457,7 @@
             mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_LOW;
         }
         mHasInvalidation = true;
+        checkIdleness();
     }
 
     /**
@@ -12494,6 +12500,7 @@
             mHandler.sendEmptyMessageDelayed(MSG_FRAME_RATE_SETTING,
                     FRAME_RATE_SETTING_REEVALUATE_TIME);
         }
+        checkIdleness();
     }
 
     /**
@@ -12599,4 +12606,14 @@
     private boolean shouldEnableDvrr() {
         return sToolkitSetFrameRateReadOnlyFlagValue && mIsFrameRatePowerSavingsBalanced;
     }
+
+    private void checkIdleness() {
+        if (!mHasIdledMessage) {
+            // Check where the display is idled periodically.
+            // If so, set the frame rate category to NO_PREFERENCE
+            mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE,
+                    FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS);
+            mHasIdledMessage = true;
+        }
+    }
 }
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index fbebe1e..561d979 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -528,28 +528,7 @@
     @FlaggedApi(Flags.FLAG_CUSTOMIZABLE_WINDOW_HEADERS)
     @NonNull
     public List<Rect> getBoundingRects(@InsetsType int typeMask) {
-        Rect[] allRects = null;
-        for (int i = FIRST; i <= LAST; i = i << 1) {
-            if ((typeMask & i) == 0) {
-                continue;
-            }
-            final Rect[] rects = mTypeBoundingRectsMap[indexOf(i)];
-            if (rects == null) {
-                continue;
-            }
-            if (allRects == null) {
-                allRects = rects;
-            } else {
-                final Rect[] concat = new Rect[allRects.length + rects.length];
-                System.arraycopy(allRects, 0, concat, 0, allRects.length);
-                System.arraycopy(rects, 0, concat, allRects.length, rects.length);
-                allRects = concat;
-            }
-        }
-        if (allRects == null) {
-            return Collections.emptyList();
-        }
-        return Arrays.asList(allRects);
+        return getBoundingRects(mTypeBoundingRectsMap, typeMask);
     }
 
     /**
@@ -577,16 +556,28 @@
      *
      * @param typeMask the insets type for which to obtain the bounding rectangles
      * @return the bounding rectangles
+     * @throws IllegalArgumentException If the caller tries to query {@link Type#ime()}. Bounding
+     *                                  rects are not available if the IME isn't visible as the
+     *                                  height of the IME is dynamic depending on the
+     *                                  {@link EditorInfo} of the currently focused view, as well
+     *                                  as the UI state of the IME.
      */
     @FlaggedApi(Flags.FLAG_CUSTOMIZABLE_WINDOW_HEADERS)
     @NonNull
     public List<Rect> getBoundingRectsIgnoringVisibility(@InsetsType int typeMask) {
+        if ((typeMask & IME) != 0) {
+            throw new IllegalArgumentException("Unable to query the bounding rects for IME");
+        }
+        return getBoundingRects(mTypeMaxBoundingRectsMap, typeMask);
+    }
+
+    private List<Rect> getBoundingRects(Rect[][] typeBoundingRectsMap, @InsetsType int typeMask) {
         Rect[] allRects = null;
         for (int i = FIRST; i <= LAST; i = i << 1) {
             if ((typeMask & i) == 0) {
                 continue;
             }
-            final Rect[] rects = mTypeMaxBoundingRectsMap[indexOf(i)];
+            final Rect[] rects = typeBoundingRectsMap[indexOf(i)];
             if (rects == null) {
                 continue;
             }
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 2b2c507..22d8ed9 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -479,13 +479,13 @@
     }
 
     @Override
-    public boolean performHapticFeedback(int effectId, boolean always) {
+    public boolean performHapticFeedback(int effectId, boolean always, boolean fromIme) {
         return false;
     }
 
     @Override
-    public void performHapticFeedbackAsync(int effectId, boolean always) {
-        performHapticFeedback(effectId, always);
+    public void performHapticFeedbackAsync(int effectId, boolean always, boolean fromIme) {
+        performHapticFeedback(effectId, always, fromIme);
     }
 
     @Override
diff --git a/core/java/android/view/accessibility/IMagnificationConnection.aidl b/core/java/android/view/accessibility/IMagnificationConnection.aidl
index aae51ab..450cf755 100644
--- a/core/java/android/view/accessibility/IMagnificationConnection.aidl
+++ b/core/java/android/view/accessibility/IMagnificationConnection.aidl
@@ -124,4 +124,9 @@
      * @param scale magnification scale.
      */
     void onUserMagnificationScaleChanged(int userId, int displayId, float scale);
+
+    /**
+     * Notify the changes of fullscreen magnification activation on the specified display
+     */
+    void onFullscreenMagnificationActivationChanged(int displayId, boolean activated);
 }
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 364c94f..64e5a5b 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -50,6 +50,7 @@
 import android.content.IntentSender;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.credentials.GetCredentialException;
 import android.credentials.GetCredentialResponse;
 import android.graphics.Rect;
 import android.metrics.LogMaker;
@@ -105,6 +106,7 @@
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.io.Serializable;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
@@ -2400,6 +2402,13 @@
 
             final Bundle responseData = new Bundle();
             responseData.putParcelable(EXTRA_AUTHENTICATION_RESULT, result);
+            Serializable exception = data.getSerializableExtra(
+                    CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION,
+                    GetCredentialException.class);
+            if (exception != null && Flags.autofillCredmanIntegration()) {
+                responseData.putSerializable(
+                        CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION, exception);
+            }
             final Bundle newClientState = data.getBundleExtra(EXTRA_CLIENT_STATE);
             if (newClientState != null) {
                 responseData.putBundle(EXTRA_CLIENT_STATE, newClientState);
@@ -2926,6 +2935,48 @@
         }
     }
 
+    private void onGetCredentialException(int sessionId, AutofillId id, String errorType,
+            String errorMsg) {
+        synchronized (mLock) {
+            if (sessionId != mSessionId) {
+                Log.w(TAG, "onGetCredentialException afm sessionIds don't match");
+                return;
+            }
+
+            final AutofillClient client = getClient();
+            if (client == null) {
+                Log.w(TAG, "onGetCredentialException afm client id null");
+                return;
+            }
+            ArrayList<AutofillId> failedIds = new ArrayList<>();
+            final View[] views = client.autofillClientFindViewsByAutofillIdTraversal(
+                    Helper.toArray(new ArrayList<>(Collections.singleton(id))));
+            if (views == null || views.length == 0) {
+                Log.w(TAG, "onGetCredentialException afm client view not found");
+                return;
+            }
+
+            final View view = views[0];
+            if (view == null) {
+                Log.i(TAG, "onGetCredentialException View is null");
+
+                // Most likely view has been removed after the initial request was sent to the
+                // the service; this is fine, but we need to update the view status in the
+                // server side so it can be triggered again.
+                Log.d(TAG, "onGetCredentialException(): no View with id " + id);
+                failedIds.add(id);
+            }
+            if (id.isVirtualInt()) {
+                Log.i(TAG, "onGetCredentialException afm client id is virtual");
+                // TODO(b/326314286): Handle virtual views
+            } else {
+                Log.i(TAG, "onGetCredentialException afm client id is NOT virtual");
+                view.onGetCredentialException(errorType, errorMsg);
+            }
+            handleFailedIdsLocked(failedIds);
+        }
+    }
+
     private void onGetCredentialResponse(int sessionId, AutofillId id,
             GetCredentialResponse response) {
         synchronized (mLock) {
@@ -4382,6 +4433,15 @@
         }
 
         @Override
+        public void onGetCredentialException(int sessionId, AutofillId id,
+                String errorType, String errorMsg) {
+            final AutofillManager afm = mAfm.get();
+            if (afm != null) {
+                afm.post(() -> afm.onGetCredentialException(sessionId, id, errorType, errorMsg));
+            }
+        }
+
+        @Override
         public void autofillContent(int sessionId, AutofillId id, ClipData content) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index e838027..904a7e0 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -49,9 +49,12 @@
     void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values,
             boolean hideHighlight);
 
-     void onGetCredentialResponse(int sessionId, in AutofillId id,
+    void onGetCredentialResponse(int sessionId, in AutofillId id,
                  in GetCredentialResponse response);
 
+    void onGetCredentialException(int sessionId, in AutofillId id,
+                     in String errorType, in String errorMsg);
+
     /**
      * Autofills the activity with rich content data (e.g. an image) from a dataset.
      */
diff --git a/core/java/android/view/flags/refresh_rate_flags.aconfig b/core/java/android/view/flags/refresh_rate_flags.aconfig
index 9d613bc..05cabd5 100644
--- a/core/java/android/view/flags/refresh_rate_flags.aconfig
+++ b/core/java/android/view/flags/refresh_rate_flags.aconfig
@@ -74,4 +74,12 @@
     description: "Feature flag for setting frame rate based on velocity"
     bug: "239979904"
     is_fixed_read_only: true
+}
+
+flag {
+    name: "toolkit_frame_rate_typing_read_only"
+    namespace: "toolkit"
+    description: "Feature flag for suppressing boost on typing"
+    bug: "239979904"
+    is_fixed_read_only: true
 }
\ No newline at end of file
diff --git a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
index 491b0e3..cedf8d0 100644
--- a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
+++ b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
@@ -25,7 +25,6 @@
 import android.annotation.RequiresPermission;
 import android.annotation.UserIdInt;
 import android.content.Context;
-import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -298,7 +297,7 @@
 
     @AnyThread
     static boolean showSoftInput(@NonNull IInputMethodClient client, @Nullable IBinder windowToken,
-            @Nullable ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
+            @NonNull ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
             int lastClickToolType, @Nullable ResultReceiver resultReceiver,
             @SoftInputShowHideReason int reason) {
         final IInputMethodManager service = getService();
@@ -315,7 +314,7 @@
 
     @AnyThread
     static boolean hideSoftInput(@NonNull IInputMethodClient client, @Nullable IBinder windowToken,
-            @Nullable ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
+            @NonNull ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
             @Nullable ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
         final IInputMethodManager service = getService();
         if (service == null) {
@@ -331,6 +330,20 @@
 
     // TODO(b/293640003): Remove method once Flags.useZeroJankProxy() is enabled.
     @AnyThread
+    @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
+    static void hideSoftInputFromServerForTest() {
+        final IInputMethodManager service = getService();
+        if (service == null) {
+            return;
+        }
+        try {
+            service.hideSoftInputFromServerForTest();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @AnyThread
     @NonNull
     @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
     static InputBindResult startInputOrWindowGainedFocus(@StartInputReason int startInputReason,
@@ -654,35 +667,18 @@
         }
     }
 
-    /** @see com.android.server.inputmethod.ImeTrackerService#onRequestShow */
+    /** @see com.android.server.inputmethod.ImeTrackerService#onStart */
     @AnyThread
     @NonNull
-    static ImeTracker.Token onRequestShow(@NonNull String tag, int uid,
+    static ImeTracker.Token onStart(@NonNull String tag, int uid, @ImeTracker.Type int type,
             @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser) {
-        final IImeTracker service = getImeTrackerService();
+        final var service = getImeTrackerService();
         if (service == null) {
-            // Create token with "fake" binder if the service was not found.
-            return new ImeTracker.Token(new Binder(), tag);
+            // Create token with "empty" binder if the service was not found.
+            return ImeTracker.Token.empty(tag);
         }
         try {
-            return service.onRequestShow(tag, uid, origin, reason, fromUser);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /** @see com.android.server.inputmethod.ImeTrackerService#onRequestHide */
-    @AnyThread
-    @NonNull
-    static ImeTracker.Token onRequestHide(@NonNull String tag, int uid,
-            @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser) {
-        final IImeTracker service = getImeTrackerService();
-        if (service == null) {
-            // Create token with "fake" binder if the service was not found.
-            return new ImeTracker.Token(new Binder(), tag);
-        }
-        try {
-            return service.onRequestHide(tag, uid, origin, reason, fromUser);
+            return service.onStart(tag, uid, type, origin, reason, fromUser);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java
index 74e1d10..d992feb 100644
--- a/core/java/android/view/inputmethod/ImeTracker.java
+++ b/core/java/android/view/inputmethod/ImeTracker.java
@@ -28,17 +28,20 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.ActivityThread;
 import android.content.Context;
+import android.os.Binder;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.Process;
 import android.os.SystemProperties;
 import android.util.Log;
 import android.view.InsetsController.AnimationType;
 import android.view.SurfaceControl;
 import android.view.View;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
 import com.android.internal.inputmethod.InputMethodDebug;
 import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.internal.jank.InteractionJankMonitor;
@@ -108,34 +111,32 @@
     /**
      * The origin of the IME request
      *
-     * The name follows the format {@code PHASE_x_...} where {@code x} denotes
-     * where the origin is (i.e. {@code PHASE_SERVER_...} occurs in the server).
+     * <p> The name follows the format {@code ORIGIN_x_...} where {@code x} denotes
+     * where the origin is (i.e. {@code ORIGIN_SERVER} occurs in the server).
      */
     @IntDef(prefix = { "ORIGIN_" }, value = {
-            ORIGIN_CLIENT_SHOW_SOFT_INPUT,
-            ORIGIN_CLIENT_HIDE_SOFT_INPUT,
-            ORIGIN_SERVER_START_INPUT,
-            ORIGIN_SERVER_HIDE_INPUT
+            ORIGIN_CLIENT,
+            ORIGIN_SERVER,
+            ORIGIN_IME
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface Origin {}
 
-    /** The IME show request originated in the client. */
-    int ORIGIN_CLIENT_SHOW_SOFT_INPUT = ImeProtoEnums.ORIGIN_CLIENT_SHOW_SOFT_INPUT;
+    /** The IME request originated in the client. */
+    int ORIGIN_CLIENT = ImeProtoEnums.ORIGIN_CLIENT;
 
-    /** The IME hide request originated in the client. */
-    int ORIGIN_CLIENT_HIDE_SOFT_INPUT = ImeProtoEnums.ORIGIN_CLIENT_HIDE_SOFT_INPUT;
+    /** The IME request originated in the server. */
+    int ORIGIN_SERVER = ImeProtoEnums.ORIGIN_SERVER;
 
-    /** The IME show request originated in the server. */
-    int ORIGIN_SERVER_START_INPUT = ImeProtoEnums.ORIGIN_SERVER_START_INPUT;
-
-    /** The IME hide request originated in the server. */
-    int ORIGIN_SERVER_HIDE_INPUT = ImeProtoEnums.ORIGIN_SERVER_HIDE_INPUT;
+    /** The IME request originated in the IME. */
+    int ORIGIN_IME = ImeProtoEnums.ORIGIN_IME;
+    /** The IME request originated in the WindowManager Shell. */
+    int ORIGIN_WM_SHELL = ImeProtoEnums.ORIGIN_WM_SHELL;
 
     /**
      * The current phase of the IME request.
      *
-     * The name follows the format {@code PHASE_x_...} where {@code x} denotes
+     * <p> The name follows the format {@code PHASE_x_...} where {@code x} denotes
      * where the phase is (i.e. {@code PHASE_SERVER_...} occurs in the server).
      */
     @IntDef(prefix = { "PHASE_" }, value = {
@@ -155,7 +156,6 @@
             PHASE_IME_SHOW_SOFT_INPUT,
             PHASE_IME_HIDE_SOFT_INPUT,
             PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE,
-            PHASE_IME_APPLY_VISIBILITY_INSETS_CONSUMER,
             PHASE_SERVER_APPLY_IME_VISIBILITY,
             PHASE_WM_SHOW_IME_RUNNER,
             PHASE_WM_SHOW_IME_READY,
@@ -182,6 +182,10 @@
             PHASE_CLIENT_ANIMATION_FINISHED_SHOW,
             PHASE_CLIENT_ANIMATION_FINISHED_HIDE,
             PHASE_WM_ABORT_SHOW_IME_POST_LAYOUT,
+            PHASE_IME_SHOW_WINDOW,
+            PHASE_IME_HIDE_WINDOW,
+            PHASE_IME_PRIVILEGED_OPERATIONS,
+            PHASE_SERVER_CURRENT_ACTIVE_IME,
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface Phase {}
@@ -224,19 +228,15 @@
     /** Dispatched from the IME wrapper to the IME. */
     int PHASE_IME_WRAPPER_DISPATCH = ImeProtoEnums.PHASE_IME_WRAPPER_DISPATCH;
 
-    /** Reached the IME' showSoftInput method. */
+    /** Reached the IME's showSoftInput method. */
     int PHASE_IME_SHOW_SOFT_INPUT = ImeProtoEnums.PHASE_IME_SHOW_SOFT_INPUT;
 
-    /** Reached the IME' hideSoftInput method. */
+    /** Reached the IME's hideSoftInput method. */
     int PHASE_IME_HIDE_SOFT_INPUT = ImeProtoEnums.PHASE_IME_HIDE_SOFT_INPUT;
 
     /** The server decided the IME should be shown. */
     int PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE = ImeProtoEnums.PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE;
 
-    /** Requested applying the IME visibility in the insets source consumer. */
-    int PHASE_IME_APPLY_VISIBILITY_INSETS_CONSUMER =
-            ImeProtoEnums.PHASE_IME_APPLY_VISIBILITY_INSETS_CONSUMER;
-
     /** Applied the IME visibility. */
     int PHASE_SERVER_APPLY_IME_VISIBILITY = ImeProtoEnums.PHASE_SERVER_APPLY_IME_VISIBILITY;
 
@@ -323,54 +323,48 @@
     int PHASE_WM_ABORT_SHOW_IME_POST_LAYOUT =
             ImeProtoEnums.PHASE_WM_ABORT_SHOW_IME_POST_LAYOUT;
 
+    /** Reached the IME's showWindow method. */
+    int PHASE_IME_SHOW_WINDOW = ImeProtoEnums.PHASE_IME_SHOW_WINDOW;
+
+    /** Reached the IME's hideWindow method. */
+    int PHASE_IME_HIDE_WINDOW = ImeProtoEnums.PHASE_IME_HIDE_WINDOW;
+
+    /** Reached the InputMethodPrivilegedOperations handler. */
+    int PHASE_IME_PRIVILEGED_OPERATIONS = ImeProtoEnums.PHASE_IME_PRIVILEGED_OPERATIONS;
+
+    /** Checked that the calling IME is the currently active IME. */
+    int PHASE_SERVER_CURRENT_ACTIVE_IME = ImeProtoEnums.PHASE_SERVER_CURRENT_ACTIVE_IME;
+
     /**
-     * Creates an IME show request tracking token.
+     * Called when an IME request is started.
      *
-     * @param component the name of the component that created the IME request, or {@code null}
-     *                  otherwise (defaulting to {@link ActivityThread#currentProcessName()}).
-     * @param uid the uid of the client that requested the IME.
-     * @param origin the origin of the IME show request.
-     * @param reason the reason why the IME show request was created.
+     * @param component the name of the component that started the request.
+     * @param uid the uid of the client that started the request.
+     * @param type the type of the request.
+     * @param origin the origin of the request.
+     * @param reason the reason for starting the request.
      * @param fromUser whether this request was created directly from user interaction.
      *
-     * @return An IME tracking token.
+     * @return An IME request tracking token.
      */
     @NonNull
-    Token onRequestShow(@Nullable String component, int uid, @Origin int origin,
+    Token onStart(@NonNull String component, int uid, @Type int type, @Origin int origin,
             @SoftInputShowHideReason int reason, boolean fromUser);
 
     /**
-     * Alias for {@link #onRequestShow(String, int, int, int, boolean)} with
-     * {@code fromUser} set to {@code false}.
-     */
-    default Token onRequestShow(@Nullable String component, int uid, @Origin int origin,
-            @SoftInputShowHideReason int reason) {
-        return onRequestShow(component, uid, origin, reason, false /* fromUser */);
-    }
-
-    /**
-     * Creates an IME hide request tracking token.
+     * Called when an IME request is started for the current process.
      *
-     * @param component the name of the component that created the IME request, or {@code null}
-     *                  otherwise (defaulting to {@link ActivityThread#currentProcessName()}).
-     * @param uid the uid of the client that requested the IME.
-     * @param origin the origin of the IME hide request.
-     * @param reason the reason why the IME hide request was created.
+     * @param type the type of the request.
+     * @param origin the origin of the request.
+     * @param reason the reason for starting the request.
      * @param fromUser whether this request was created directly from user interaction.
      *
-     * @return An IME tracking token.
+     * @return An IME request tracking token.
      */
     @NonNull
-    Token onRequestHide(@Nullable String component, int uid, @Origin int origin,
-            @SoftInputShowHideReason int reason, boolean fromUser);
-
-    /**
-     * Alias for {@link #onRequestHide(String, int, int, int, boolean)} with
-     * {@code fromUser} set to {@code false}.
-     */
-    default Token onRequestHide(@Nullable String component, int uid, @Origin int origin,
-            @SoftInputShowHideReason int reason) {
-        return onRequestHide(component, uid, origin, reason, false /* fromUser */);
+    default Token onStart(@Type int type, @Origin int origin, @SoftInputShowHideReason int reason,
+            boolean fromUser) {
+        return onStart(Process.myProcessName(), Process.myUid(), type, origin, reason, fromUser);
     }
 
     /**
@@ -408,14 +402,14 @@
     /**
      * Called when the IME show request is successful.
      *
-     * @param token the token tracking the current IME show request or {@code null} otherwise.
+     * @param token the token tracking the current IME request or {@code null} otherwise.
      */
     void onShown(@Nullable Token token);
 
     /**
      * Called when the IME hide request is successful.
      *
-     * @param token the token tracking the current IME hide request or {@code null} otherwise.
+     * @param token the token tracking the current IME request or {@code null} otherwise.
      */
     void onHidden(@Nullable Token token);
 
@@ -497,33 +491,17 @@
 
         @NonNull
         @Override
-        public Token onRequestShow(@Nullable String component, int uid, @Origin int origin,
+        public Token onStart(@NonNull String component, int uid, @Type int type, @Origin int origin,
                 @SoftInputShowHideReason int reason, boolean fromUser) {
-            final var tag = getTag(component);
-            final var token = IInputMethodManagerGlobalInvoker.onRequestShow(tag, uid, origin,
-                    reason, fromUser);
+            final var tag = Token.createTag(component);
+            final var token = IInputMethodManagerGlobalInvoker.onStart(tag, uid, type,
+                    origin, reason, fromUser);
 
-            Log.i(TAG, token.mTag + ": onRequestShow at " + Debug.originToString(origin)
+            Log.i(TAG, token.mTag + ": onRequest" + (type == TYPE_SHOW ? "Show" : "Hide")
+                    + " at " + Debug.originToString(origin)
                     + " reason " + InputMethodDebug.softInputDisplayReasonToString(reason)
                     + " fromUser " + fromUser,
                     mLogStackTrace ? new Throwable() : null);
-
-            return token;
-        }
-
-        @NonNull
-        @Override
-        public Token onRequestHide(@Nullable String component, int uid, @Origin int origin,
-                @SoftInputShowHideReason int reason, boolean fromUser) {
-            final var tag = getTag(component);
-            final var token = IInputMethodManagerGlobalInvoker.onRequestHide(tag, uid, origin,
-                    reason, fromUser);
-
-            Log.i(TAG, token.mTag + ": onRequestHide at " + Debug.originToString(origin)
-                    + " reason " + InputMethodDebug.softInputDisplayReasonToString(reason)
-                    + " fromUser " + fromUser,
-                    mLogStackTrace ? new Throwable() : null);
-
             return token;
         }
 
@@ -574,20 +552,6 @@
 
             Log.i(TAG, token.mTag + ": onHidden");
         }
-
-        /**
-         * Returns a logging tag using the given component name.
-         *
-         * @param component the name of the component that created the IME request, or {@code null}
-         *                  otherwise (defaulting to {@link ActivityThread#currentProcessName()}).
-         */
-        @NonNull
-        private String getTag(@Nullable String component) {
-            if (component == null) {
-                component = ActivityThread.currentProcessName();
-            }
-            return component + ":" + Integer.toHexString(ThreadLocalRandom.current().nextInt());
-        }
     };
 
     /** The singleton IME tracker instance for instrumenting jank metrics. */
@@ -599,6 +563,10 @@
     /** A token that tracks the progress of an IME request. */
     final class Token implements Parcelable {
 
+        /** Empty binder, lazily initialized, used for empty token instantiation. */
+        @Nullable
+        private static IBinder sEmptyBinder;
+
         /** The binder used to identify this token. */
         @NonNull
         private final IBinder mBinder;
@@ -617,16 +585,56 @@
             mTag = in.readString8();
         }
 
+        /** Returns the binder used to identify this token. */
         @NonNull
         public IBinder getBinder() {
             return mBinder;
         }
 
+        /** Returns the logging tag of this token. */
         @NonNull
         public String getTag() {
             return mTag;
         }
 
+        /**
+         * Creates a logging tag.
+         *
+         * @param component the name of the component that created the IME request.
+         */
+        @NonNull
+        private static String createTag(@NonNull String component) {
+            return component + ":" + Integer.toHexString(ThreadLocalRandom.current().nextInt());
+        }
+
+        /** Returns a new token with an empty binder. */
+        @NonNull
+        @VisibleForTesting(visibility = Visibility.PACKAGE)
+        public static Token empty() {
+            final var tag = createTag(Process.myProcessName());
+            return empty(tag);
+        }
+
+        /** Returns a new token with an empty binder and the given logging tag. */
+        @NonNull
+        static Token empty(@NonNull String tag) {
+            return new Token(getEmptyBinder(), tag);
+        }
+
+        /** Returns the empty binder instance for empty token creation, lazily initializing it. */
+        @NonNull
+        private static IBinder getEmptyBinder() {
+            if (sEmptyBinder == null) {
+                sEmptyBinder = new Binder();
+            }
+            return sEmptyBinder;
+        }
+
+        @Override
+        public String toString() {
+            return super.toString() + "(tag: " + mTag + ")";
+        }
+
         /** For Parcelable, no special marshalled objects. */
         @Override
         public int describeContents() {
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 33f34c5..88607fc 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -281,7 +281,7 @@
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface ShowFlags {}
-    
+
     /**
      * Flag for {@link #showSoftInput}: this show has been explicitly
      * requested by the user.  If not set, the system has decided it may be
@@ -314,18 +314,18 @@
      * @param showInputToken an opaque {@link android.os.Binder} token to identify which API call
      *        of {@link InputMethodManager#showSoftInput(View, int)} is associated with
      *        this callback.
-     * @param statsToken the token tracking the current IME show request or {@code null} otherwise.
+     * @param statsToken the token tracking the current IME request.
      * @hide
      */
     @MainThread
     public default void showSoftInputWithToken(@ShowFlags int flags, ResultReceiver resultReceiver,
-            IBinder showInputToken, @Nullable ImeTracker.Token statsToken) {
+            IBinder showInputToken, @NonNull ImeTracker.Token statsToken) {
         showSoftInput(flags, resultReceiver);
     }
 
     /**
      * Request that any soft input part of the input method be shown to the user.
-     * 
+     *
      * @param resultReceiver The client requesting the show may wish to
      * be told the impact of their request, which should be supplied here.
      * The result code should be
@@ -352,12 +352,12 @@
      * @param hideInputToken an opaque {@link android.os.Binder} token to identify which API call
      *         of {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)}} is associated
      *         with this callback.
-     * @param statsToken the token tracking the current IME hide request or {@code null} otherwise.
+     * @param statsToken the token tracking the current IME request.
      * @hide
      */
     @MainThread
     public default void hideSoftInputWithToken(int flags, ResultReceiver resultReceiver,
-            IBinder hideInputToken, @Nullable ImeTracker.Token statsToken) {
+            IBinder hideInputToken, @NonNull ImeTracker.Token statsToken) {
         hideSoftInput(flags, resultReceiver);
     }
 
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 7c9678f..16fecc1 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -497,6 +497,25 @@
      * @hide
      */
     @TestApi
+    public InputMethodInfo(@NonNull String packageName, @NonNull String className,
+            @NonNull CharSequence label, @NonNull String settingsActivity,
+            @NonNull String languageSettingsActivity, boolean supportStylusHandwriting,
+            @NonNull String stylusHandwritingSettingsActivityAttr) {
+        this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
+                settingsActivity, languageSettingsActivity, null /* subtypes */,
+                0 /* isDefaultResId */, false /* forceDefault */,
+                true /* supportsSwitchingToNextInputMethod */,
+                false /* inlineSuggestionsEnabled */, false /* isVrOnly */,
+                false /* isVirtualDeviceOnly */, 0 /* handledConfigChanges */,
+                supportStylusHandwriting, false /* supportConnectionlessStylusHandwriting */,
+                stylusHandwritingSettingsActivityAttr, false /* inlineSuggestionsEnabled */);
+    }
+
+    /**
+     * Test API for creating a built-in input method to verify stylus handwriting.
+     * @hide
+     */
+    @TestApi
     @FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING)
     public InputMethodInfo(@NonNull String packageName, @NonNull String className,
             @NonNull CharSequence label, @NonNull String settingsActivity,
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 3bce155..3be76cc 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1153,6 +1153,7 @@
                     }
                     final boolean startInput;
                     synchronized (mH) {
+                        mImeDispatcher.clear();
                         if (getBindSequenceLocked() != sequence) {
                             return;
                         }
@@ -2262,21 +2263,22 @@
      * {@link #RESULT_HIDDEN}.
      */
     public boolean showSoftInput(View view, @ShowFlags int flags, ResultReceiver resultReceiver) {
-        return showSoftInput(view, null /* statsToken */, flags, resultReceiver,
-                SoftInputShowHideReason.SHOW_SOFT_INPUT);
+        return showSoftInput(view, flags, resultReceiver, SoftInputShowHideReason.SHOW_SOFT_INPUT);
     }
 
-    private boolean showSoftInput(View view, @Nullable ImeTracker.Token statsToken,
-            @ShowFlags int flags, ResultReceiver resultReceiver,
+    private boolean showSoftInput(View view, @ShowFlags int flags,
+            @Nullable ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
+        // TODO(b/303041796): handle tracking physical keyboard and DPAD as user interactions
+        final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_SHOW,
+                ImeTracker.ORIGIN_CLIENT, reason, ImeTracker.isFromUser(view));
+        return showSoftInput(view, statsToken, flags, resultReceiver, reason);
+    }
+
+    private boolean showSoftInput(View view, @NonNull ImeTracker.Token statsToken,
+            @ShowFlags int flags, @Nullable ResultReceiver resultReceiver,
             @SoftInputShowHideReason int reason) {
-        if (statsToken == null) {
-            // TODO(b/303041796): handle tracking physical keyboard and DPAD as user interactions
-            statsToken = ImeTracker.forLogging().onRequestShow(null /* component */,
-                    Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT, reason,
-                    ImeTracker.isFromUser(view));
-        }
-        ImeTracker.forLatency().onRequestShow(statsToken, ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
-                reason, ActivityThread::currentApplication);
+        ImeTracker.forLatency().onRequestShow(statsToken,
+                ImeTracker.ORIGIN_CLIENT, reason, ActivityThread::currentApplication);
         ImeTracing.getInstance().triggerClientDump("InputMethodManager#showSoftInput", this,
                 null /* icProto */);
         // Re-dispatch if there is a context mismatch.
@@ -2289,9 +2291,8 @@
         synchronized (mH) {
             if (!hasServedByInputMethodLocked(view)) {
                 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
-                ImeTracker.forLatency().onShowFailed(
-                        statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED,
-                        ActivityThread::currentApplication);
+                ImeTracker.forLatency().onShowFailed(statsToken,
+                        ImeTracker.PHASE_CLIENT_VIEW_SERVED, ActivityThread::currentApplication);
                 Log.w(TAG, "Ignoring showSoftInput() as view=" + view + " is not served.");
                 return false;
             }
@@ -2326,9 +2327,9 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768499)
     public void showSoftInputUnchecked(@ShowFlags int flags, ResultReceiver resultReceiver) {
         synchronized (mH) {
-            final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestShow(
-                    null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
-                    SoftInputShowHideReason.SHOW_SOFT_INPUT);
+            final int reason = SoftInputShowHideReason.SHOW_SOFT_INPUT;
+            final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_SHOW,
+                    ImeTracker.ORIGIN_CLIENT, reason, false /* fromUser */);
 
             Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be"
                     + " removed soon. If you are using androidx.appcompat.widget.SearchView,"
@@ -2352,7 +2353,7 @@
                     flags,
                     mCurRootView.getLastClickToolType(),
                     resultReceiver,
-                    SoftInputShowHideReason.SHOW_SOFT_INPUT);
+                    reason);
         }
     }
 
@@ -2428,11 +2429,10 @@
             initialServedView = getServedViewLocked();
         }
 
-        final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide(
-                null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
-                reason, ImeTracker.isFromUser(initialServedView));
-        ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
-                reason, ActivityThread::currentApplication);
+        final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+                ImeTracker.ORIGIN_CLIENT, reason, ImeTracker.isFromUser(initialServedView));
+        ImeTracker.forLatency().onRequestHide(statsToken,
+                ImeTracker.ORIGIN_CLIENT, reason, ActivityThread::currentApplication);
         ImeTracing.getInstance().triggerClientDump("InputMethodManager#hideSoftInputFromWindow",
                 this, null /* icProto */);
         checkFocus();
@@ -2471,20 +2471,18 @@
             }
         }
 
-        final var reason = SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_VIEW;
-        final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide(
-                null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
-                reason, ImeTracker.isFromUser(view));
-        ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
-                reason, ActivityThread::currentApplication);
+        final int reason = SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_VIEW;
+        final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+                ImeTracker.ORIGIN_CLIENT, reason, ImeTracker.isFromUser(view));
+        ImeTracker.forLatency().onRequestHide(statsToken,
+                ImeTracker.ORIGIN_CLIENT, reason, ActivityThread::currentApplication);
         ImeTracing.getInstance().triggerClientDump("InputMethodManager#hideSoftInputFromView",
                 this, null /* icProto */);
         synchronized (mH) {
             if (!hasServedByInputMethodLocked(view)) {
                 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
-                ImeTracker.forLatency().onShowFailed(
-                        statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED,
-                        ActivityThread::currentApplication);
+                ImeTracker.forLatency().onShowFailed(statsToken,
+                        ImeTracker.PHASE_CLIENT_VIEW_SERVED, ActivityThread::currentApplication);
                 Log.w(TAG, "Ignoring hideSoftInputFromView() as view=" + view + " is not served.");
                 return false;
             }
@@ -2497,6 +2495,19 @@
     }
 
     /**
+     * A test API for CTS to request hiding the current soft input window, with the request origin
+     * on the server side.
+     *
+     * @hide
+     */
+    @SuppressLint("UnflaggedApi") // @TestApi without associated feature.
+    @TestApi
+    @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
+    public void hideSoftInputFromServerForTest() {
+        IInputMethodManagerGlobalInvoker.hideSoftInputFromServerForTest();
+    }
+
+    /**
      * Start stylus handwriting session.
      *
      * If supported by the current input method, a stylus handwriting session is started on the
@@ -2972,10 +2983,11 @@
             if (view != null) {
                 final WindowInsets rootInsets = view.getRootWindowInsets();
                 if (rootInsets != null && rootInsets.isVisible(WindowInsets.Type.ime())) {
-                    hideSoftInputFromWindow(view.getWindowToken(), hideFlags, null,
+                    hideSoftInputFromWindow(view.getWindowToken(), hideFlags,
+                            null /* resultReceiver */,
                             SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT);
                 } else {
-                    showSoftInput(view, null /* statsToken */, showFlags, null /* resultReceiver */,
+                    showSoftInput(view, showFlags, null /* resultReceiver */,
                             SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT);
                 }
             }
@@ -3490,8 +3502,7 @@
             return false;
         }
         mServedView = mNextServedView;
-        if (initiationWithoutInputConnection() && mServedView.onCheckIsTextEditor()
-                && mServedView.isHandwritingDelegate()) {
+        if (initiationWithoutInputConnection() && mServedView.isHandwritingDelegate()) {
             mServedView.getViewRootImpl().getHandwritingInitiator().onDelegateViewFocused(
                     mServedView);
         }
@@ -3537,11 +3548,11 @@
 
     @UnsupportedAppUsage
     void closeCurrentInput() {
-        final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide(
-                null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
-                SoftInputShowHideReason.HIDE_CLOSE_CURRENT_SESSION);
-        ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
-                SoftInputShowHideReason.HIDE_CLOSE_CURRENT_SESSION,
+        final int reason = SoftInputShowHideReason.HIDE_CLOSE_CURRENT_SESSION;
+        final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+                ImeTracker.ORIGIN_CLIENT, reason, false /* fromUser */);
+        ImeTracker.forLatency().onRequestHide(statsToken,
+                ImeTracker.ORIGIN_CLIENT, reason,
                 ActivityThread::currentApplication);
 
         synchronized (mH) {
@@ -3562,7 +3573,7 @@
                     statsToken,
                     HIDE_NOT_ALWAYS,
                     null,
-                    SoftInputShowHideReason.HIDE_CLOSE_CURRENT_SESSION);
+                    reason);
         }
     }
 
@@ -3603,12 +3614,12 @@
      *
      * @param windowToken the window from which this request originates. If this doesn't match the
      *                    currently served view, the request is ignored and returns {@code false}.
-     * @param statsToken the token tracking the current IME show request or {@code null} otherwise.
+     * @param statsToken the token tracking the current IME request.
      *
      * @return {@code true} if IME can (eventually) be shown, {@code false} otherwise.
      * @hide
      */
-    public boolean requestImeShow(IBinder windowToken, @Nullable ImeTracker.Token statsToken) {
+    public boolean requestImeShow(IBinder windowToken, @NonNull ImeTracker.Token statsToken) {
         checkFocus();
         synchronized (mH) {
             final View servedView = getServedViewLocked();
@@ -3632,16 +3643,11 @@
      *
      * @param windowToken the window from which this request originates. If this doesn't match the
      *                    currently served view, the request is ignored.
-     * @param statsToken the token tracking the current IME show request or {@code null} otherwise.
+     * @param statsToken the token tracking the current IME request.
      * @hide
      */
-    public void notifyImeHidden(IBinder windowToken, @Nullable ImeTracker.Token statsToken) {
-        if (statsToken == null) {
-            statsToken = ImeTracker.forLogging().onRequestHide(null /* component */,
-                    Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
-                    SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API);
-        }
-        ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
+    public void notifyImeHidden(IBinder windowToken, @NonNull ImeTracker.Token statsToken) {
+        ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT,
                 SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API,
                 ActivityThread::currentApplication);
         ImeTracing.getInstance().triggerClientDump("InputMethodManager#notifyImeHidden", this,
@@ -4025,8 +4031,11 @@
      */
     @Deprecated
     public void hideSoftInputFromInputMethod(IBinder token, @HideFlags int flags) {
-        InputMethodPrivilegedOperationsRegistry.get(token).hideMySoftInput(
-                flags, SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION);
+        final int reason = SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION;
+        final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+                ImeTracker.ORIGIN_CLIENT, reason, false /* fromUser */);
+        InputMethodPrivilegedOperationsRegistry.get(token).hideMySoftInput(statsToken, flags,
+                reason);
     }
 
     /**
@@ -4044,7 +4053,11 @@
      */
     @Deprecated
     public void showSoftInputFromInputMethod(IBinder token, @ShowFlags int flags) {
-        InputMethodPrivilegedOperationsRegistry.get(token).showMySoftInput(flags);
+        final int reason = SoftInputShowHideReason.SHOW_SOFT_INPUT_IMM_DEPRECATION;
+        final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_SHOW,
+                ImeTracker.ORIGIN_CLIENT, reason, false /* fromUser */);
+        InputMethodPrivilegedOperationsRegistry.get(token).showMySoftInput(statsToken, flags,
+                reason);
     }
 
     /**
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 13dc4ef..fe4ac4e 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1105,6 +1105,7 @@
         SetRemoteCollectionItemListAdapterAction(Parcel parcel) {
             mViewId = parcel.readInt();
             mIntentId = parcel.readInt();
+            mIsReplacedIntoAction = parcel.readBoolean();
             mServiceIntent = parcel.readTypedObject(Intent.CREATOR);
             mItems = mServiceIntent != null
                     ? null
@@ -1128,6 +1129,7 @@
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(mViewId);
             dest.writeInt(mIntentId);
+            dest.writeBoolean(mIsReplacedIntoAction);
             dest.writeTypedObject(mServiceIntent, flags);
             if (mItems != null) {
                 mItems.writeToParcel(dest, flags, /* attached= */ true);
@@ -1209,6 +1211,19 @@
     }
 
     /**
+     * The maximum size for RemoteViews with converted RemoteCollectionItemsAdapter.
+     * When converting RemoteViewsAdapter to RemoteCollectionItemsAdapter, we want to put size
+     * limits on each unique RemoteCollectionItems in order to not exceed the transaction size limit
+     * for each parcel (typically 1 MB). We leave a certain ratio of the maximum size as a buffer
+     * for missing calculations of certain parameters (e.g. writing a RemoteCollectionItems to the
+     * parcel will write its Id array as well, but that is missing when writing itschild RemoteViews
+     * directly to the parcel as we did in RemoteViewsService)
+     *
+     * @hide
+     */
+    private static final int MAX_SINGLE_PARCEL_SIZE = (int) (1_000_000 * 0.8);
+
+    /**
      * @hide
      */
     public CompletableFuture<Void> collectAllIntents() {
@@ -1260,17 +1275,47 @@
             return mUriToCollectionMapping.get(uri);
         }
 
-        CompletableFuture<Void> collectAllIntentsNoComplete(@NonNull RemoteViews inViews) {
-            CompletableFuture<Void> collectionFuture = CompletableFuture.completedFuture(null);
+        public @NonNull CompletableFuture<Void> collectAllIntentsNoComplete(
+                @NonNull RemoteViews inViews) {
+            SparseArray<Intent> idToIntentMapping = new SparseArray<>();
+            // Collect the number of uinque Intent (which is equal to the number of new connections
+            // to make) for size allocation and exclude certain collections from being written to
+            // the parcel to better estimate the space left for reallocation.
+            collectAllIntentsInternal(inViews, idToIntentMapping);
+
+            // Calculate the individual size here
+            int numOfIntents = idToIntentMapping.size();
+            if (numOfIntents == 0) {
+                Log.e(LOG_TAG, "Possibly notifying updates for nonexistent view Id");
+                return CompletableFuture.completedFuture(null);
+            }
+
+            Parcel sizeTestParcel = Parcel.obtain();
+            // Write self RemoteViews to the parcel, which includes the actions/bitmaps/collection
+            // cache to see how much space is left for the RemoteCollectionItems that are to be
+            // updated.
+            RemoteViews.this.writeToParcel(sizeTestParcel,
+                    /* flags= */ 0,
+                    /* intentsToIgnore= */ idToIntentMapping);
+            int remainingSize = MAX_SINGLE_PARCEL_SIZE - sizeTestParcel.dataSize();
+            sizeTestParcel.recycle();
+
+            int individualSize = remainingSize < 0
+                    ? 0
+                    : remainingSize / numOfIntents;
+
+            return connectAllUniqueIntents(individualSize, idToIntentMapping);
+        }
+
+        private void collectAllIntentsInternal(@NonNull RemoteViews inViews,
+                @NonNull SparseArray<Intent> idToIntentMapping) {
             if (inViews.hasSizedRemoteViews()) {
                 for (RemoteViews remoteViews : inViews.mSizedRemoteViews) {
-                    collectionFuture = CompletableFuture.allOf(collectionFuture,
-                            collectAllIntentsNoComplete(remoteViews));
+                    collectAllIntentsInternal(remoteViews, idToIntentMapping);
                 }
             } else if (inViews.hasLandscapeAndPortraitLayouts()) {
-                collectionFuture = CompletableFuture.allOf(
-                        collectAllIntentsNoComplete(inViews.mLandscape),
-                        collectAllIntentsNoComplete(inViews.mPortrait));
+                collectAllIntentsInternal(inViews.mLandscape, idToIntentMapping);
+                collectAllIntentsInternal(inViews.mPortrait, idToIntentMapping);
             } else if (inViews.mActions != null) {
                 for (Action action : inViews.mActions) {
                     if (action instanceof SetRemoteCollectionItemListAdapterAction rca) {
@@ -1280,13 +1325,16 @@
                         }
 
                         if (rca.mIntentId != -1 && rca.mIsReplacedIntoAction) {
-                            final String uri = mIdToUriMapping.get(rca.mIntentId);
-                            collectionFuture = CompletableFuture.allOf(collectionFuture,
-                                    getItemsFutureFromIntentWithTimeout(rca.mServiceIntent)
-                                            .thenAccept(rc -> {
-                                                rc.setHierarchyRootData(getHierarchyRootData());
-                                                mUriToCollectionMapping.put(uri, rc);
-                                            }));
+                            rca.mIsReplacedIntoAction = false;
+
+                            // Avoid redundant connections for the same intent. Also making sure
+                            // that the number of connections we are making is always equal to the
+                            // nmuber of unique intents that are being used for the updates.
+                            if (idToIntentMapping.contains(rca.mIntentId)) {
+                                continue;
+                            }
+
+                            idToIntentMapping.put(rca.mIntentId, rca.mServiceIntent);
                             rca.mItems = null;
                             continue;
                         }
@@ -1295,7 +1343,7 @@
                         // intents.
                         if (rca.mServiceIntent != null) {
                             final String uri = rca.mServiceIntent.toUri(0);
-                            int index = mIdToUriMapping.indexOfValue(uri);
+                            int index = mIdToUriMapping.indexOfValueByValue(uri);
                             if (index == -1) {
                                 int newIntentId = mIdToUriMapping.size();
                                 rca.mIntentId = newIntentId;
@@ -1305,41 +1353,50 @@
                                 rca.mItems = null;
                                 continue;
                             }
-                            collectionFuture = CompletableFuture.allOf(collectionFuture,
-                                    getItemsFutureFromIntentWithTimeout(rca.mServiceIntent)
-                                            .thenAccept(rc -> {
-                                                rc.setHierarchyRootData(getHierarchyRootData());
-                                                mUriToCollectionMapping.put(uri, rc);
-                                            }));
+
+                            idToIntentMapping.put(rca.mIntentId, rca.mServiceIntent);
                             rca.mItems = null;
                         } else {
                             for (RemoteViews views : rca.mItems.mViews) {
-                                collectionFuture = CompletableFuture.allOf(collectionFuture,
-                                        collectAllIntentsNoComplete(views));
+                                collectAllIntentsInternal(views, idToIntentMapping);
                             }
                         }
                     } else if (action instanceof ViewGroupActionAdd vgaa
                             && vgaa.mNestedViews != null) {
-                        collectionFuture = CompletableFuture.allOf(collectionFuture,
-                                collectAllIntentsNoComplete(vgaa.mNestedViews));
+                        collectAllIntentsInternal(vgaa.mNestedViews, idToIntentMapping);
                     }
                 }
             }
+        }
 
-            return collectionFuture;
+        private @NonNull CompletableFuture<Void> connectAllUniqueIntents(int individualSize,
+                @NonNull SparseArray<Intent> idToIntentMapping) {
+            List<CompletableFuture<Void>> intentFutureList = new ArrayList<>();
+            for (int i = 0; i < idToIntentMapping.size(); i++) {
+                String currentIntentUri = mIdToUriMapping.get(idToIntentMapping.keyAt(i));
+                Intent currentIntent = idToIntentMapping.valueAt(i);
+                intentFutureList.add(getItemsFutureFromIntentWithTimeout(currentIntent,
+                        individualSize)
+                        .thenAccept(items -> {
+                            items.setHierarchyRootData(getHierarchyRootData());
+                            mUriToCollectionMapping.put(currentIntentUri, items);
+                        }));
+            }
+
+            return CompletableFuture.allOf(intentFutureList.toArray(CompletableFuture[]::new));
         }
 
         private static CompletableFuture<RemoteCollectionItems> getItemsFutureFromIntentWithTimeout(
-                Intent intent) {
+                Intent intent, int individualSize) {
             if (intent == null) {
                 Log.e(LOG_TAG, "Null intent received when generating adapter future");
                 return CompletableFuture.completedFuture(new RemoteCollectionItems
-                    .Builder().build());
+                        .Builder().build());
             }
 
             final Context context = ActivityThread.currentApplication();
-            final CompletableFuture<RemoteCollectionItems> result = new CompletableFuture<>();
 
+            final CompletableFuture<RemoteCollectionItems> result = new CompletableFuture<>();
             context.bindService(intent, Context.BindServiceFlags.of(Context.BIND_AUTO_CREATE),
                     result.defaultExecutor(), new ServiceConnection() {
                         @Override
@@ -1348,11 +1405,11 @@
                             RemoteCollectionItems items;
                             try {
                                 items = IRemoteViewsFactory.Stub.asInterface(iBinder)
-                                    .getRemoteCollectionItems();
+                                        .getRemoteCollectionItems(individualSize);
                             } catch (RemoteException re) {
                                 items = new RemoteCollectionItems.Builder().build();
-                                Log.e(LOG_TAG, "Error getting collection items from the factory",
-                                        re);
+                                Log.e(LOG_TAG, "Error getting collection items from the"
+                                        + " factory", re);
                             } finally {
                                 context.unbindService(this);
                             }
@@ -1371,10 +1428,17 @@
             return result;
         }
 
-        public void writeToParcel(Parcel out, int flags) {
+        public void writeToParcel(Parcel out, int flags,
+                @Nullable SparseArray<Intent> intentsToIgnore) {
             out.writeInt(mIdToUriMapping.size());
             for (int i = 0; i < mIdToUriMapping.size(); i++) {
-                out.writeInt(mIdToUriMapping.keyAt(i));
+                int currentIntentId = mIdToUriMapping.keyAt(i);
+                if (intentsToIgnore != null && intentsToIgnore.contains(currentIntentId)) {
+                    // Skip writing collections that are to be updated in the following steps to
+                    // better estimate the RemoteViews size.
+                    continue;
+                }
+                out.writeInt(currentIntentId);
                 String intentUri = mIdToUriMapping.valueAt(i);
                 out.writeString8(intentUri);
                 mUriToCollectionMapping.get(intentUri).writeToParcel(out, flags, true);
@@ -3874,7 +3938,7 @@
         }
     }
 
-    private static class SetDrawInstructionAction extends Action {
+    private class SetDrawInstructionAction extends Action {
 
         @Nullable
         private final DrawInstructions mInstructions;
@@ -3909,6 +3973,15 @@
                 }
                 try (ByteArrayInputStream is = new ByteArrayInputStream(bytes.get(0))) {
                     player.setDocument(new RemoteComposeDocument(is));
+                    player.addClickListener((viewId, metadata) -> {
+                        mActions.forEach(action -> {
+                            if (viewId == action.mViewId
+                                    && action instanceof SetOnClickResponse setOnClickResponse) {
+                                setOnClickResponse.mResponse.handleViewInteraction(
+                                        player, params.handler);
+                            }
+                        });
+                    });
                 } catch (IOException e) {
                     Log.e(LOG_TAG, "Failed to render draw instructions", e);
                 }
@@ -6051,16 +6124,6 @@
         RemoteViews rvToApply = getRemoteViewsToApply(context, size);
         View result = inflateView(context, rvToApply, directParent,
                 params.applyThemeResId, params.colorResources);
-        if (result instanceof RemoteComposePlayer player) {
-            player.addClickListener((viewId, metadata) -> {
-                mActions.forEach(action -> {
-                    if (viewId == action.mViewId
-                            && action instanceof SetOnClickResponse setOnClickResponse) {
-                        setOnClickResponse.mResponse.handleViewInteraction(player, params.handler);
-                    }
-                });
-            });
-        }
         rvToApply.performApply(result, rootParent, params);
         return result;
     }
@@ -6725,7 +6788,13 @@
         return 0;
     }
 
+    @Override
     public void writeToParcel(Parcel dest, int flags) {
+        writeToParcel(dest, flags, /* intentsToIgnore= */ null);
+    }
+
+    private void writeToParcel(Parcel dest, int flags,
+            @Nullable SparseArray<Intent> intentsToIgnore) {
         boolean prevSquashingAllowed = dest.allowSquashing();
 
         if (!hasMultipleLayouts()) {
@@ -6734,7 +6803,7 @@
             // is shared by all children.
             if (mIsRoot) {
                 mBitmapCache.writeBitmapsToParcel(dest, flags);
-                mCollectionCache.writeToParcel(dest, flags);
+                mCollectionCache.writeToParcel(dest, flags, intentsToIgnore);
             }
             mApplication.writeToParcel(dest, flags);
             if (mIsRoot || mIdealSize == null) {
@@ -6751,7 +6820,7 @@
             dest.writeInt(MODE_HAS_SIZED_REMOTEVIEWS);
             if (mIsRoot) {
                 mBitmapCache.writeBitmapsToParcel(dest, flags);
-                mCollectionCache.writeToParcel(dest, flags);
+                mCollectionCache.writeToParcel(dest, flags, intentsToIgnore);
             }
             dest.writeInt(mSizedRemoteViews.size());
             for (RemoteViews view : mSizedRemoteViews) {
@@ -6763,7 +6832,7 @@
             // is shared by all children.
             if (mIsRoot) {
                 mBitmapCache.writeBitmapsToParcel(dest, flags);
-                mCollectionCache.writeToParcel(dest, flags);
+                mCollectionCache.writeToParcel(dest, flags, intentsToIgnore);
             }
             mLandscape.writeToParcel(dest, flags);
             // Both RemoteViews already share the same package and user
diff --git a/core/java/android/widget/RemoteViewsService.java b/core/java/android/widget/RemoteViewsService.java
index a250a86..d4a5bbd 100644
--- a/core/java/android/widget/RemoteViewsService.java
+++ b/core/java/android/widget/RemoteViewsService.java
@@ -19,6 +19,7 @@
 import android.app.Service;
 import android.content.Intent;
 import android.os.IBinder;
+import android.os.Parcel;
 
 import com.android.internal.widget.IRemoteViewsFactory;
 
@@ -43,13 +44,6 @@
     private static final Object sLock = new Object();
 
     /**
-     * Used for determining the maximum number of entries to retrieve from RemoteViewsFactory
-     *
-     * @hide
-     */
-    private static final int MAX_NUM_ENTRY = 10;
-
-    /**
      * An interface for an adapter between a remote collection view (ListView, GridView, etc) and
      * the underlying data for that view.  The implementor is responsible for making a RemoteView
      * for each item in the data set. This interface is a thin wrapper around {@link Adapter}.
@@ -235,9 +229,10 @@
         }
 
         @Override
-        public RemoteViews.RemoteCollectionItems getRemoteCollectionItems() {
+        public RemoteViews.RemoteCollectionItems getRemoteCollectionItems(int capSize) {
             RemoteViews.RemoteCollectionItems items = new RemoteViews.RemoteCollectionItems
                     .Builder().build();
+            Parcel capSizeTestParcel = Parcel.obtain();
 
             try {
                 RemoteViews.RemoteCollectionItems.Builder itemsBuilder =
@@ -245,15 +240,25 @@
                 mFactory.onDataSetChanged();
 
                 itemsBuilder.setHasStableIds(mFactory.hasStableIds());
-                final int numOfEntries = Math.min(mFactory.getCount(), MAX_NUM_ENTRY);
+                final int numOfEntries = mFactory.getCount();
+
                 for (int i = 0; i < numOfEntries; i++) {
-                    itemsBuilder.addItem(mFactory.getItemId(i), mFactory.getViewAt(i));
+                    final long currentItemId = mFactory.getItemId(i);
+                    final RemoteViews currentView = mFactory.getViewAt(i);
+                    currentView.writeToParcel(capSizeTestParcel, 0);
+                    if (capSizeTestParcel.dataSize() > capSize) {
+                        break;
+                    }
+                    itemsBuilder.addItem(currentItemId, currentView);
                 }
 
                 items = itemsBuilder.build();
             } catch (Exception ex) {
                 Thread t = Thread.currentThread();
                 Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
+            } finally {
+                // Recycle the parcel
+                capSizeTestParcel.recycle();
             }
             return items;
         }
diff --git a/core/java/android/widget/flags/notification_widget_flags.aconfig b/core/java/android/widget/flags/notification_widget_flags.aconfig
index bfe3d05..e60fa15 100644
--- a/core/java/android/widget/flags/notification_widget_flags.aconfig
+++ b/core/java/android/widget/flags/notification_widget_flags.aconfig
@@ -15,4 +15,14 @@
   metadata {
     purpose: PURPOSE_BUGFIX
   }
+}
+
+flag {
+  name: "conversation_style_set_avatar_async"
+  namespace: "systemui"
+  description: "Offloads conversation avatar drawable loading to the background thread"
+  bug: "305540309"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
 }
\ No newline at end of file
diff --git a/core/java/android/window/flags/OWNERS b/core/java/android/window/flags/OWNERS
index 3fa3760..fd73d35 100644
--- a/core/java/android/window/flags/OWNERS
+++ b/core/java/android/window/flags/OWNERS
@@ -1,2 +1,3 @@
 per-file responsible_apis.aconfig = file:/BAL_OWNERS
 per-file large_screen_experiences_app_compat.aconfig = file:/LSE_APP_COMPAT_OWNERS
+per-file accessibility.aconfig = file:/core/java/android/view/accessibility/OWNERS
diff --git a/core/java/android/window/flags/accessibility.aconfig b/core/java/android/window/flags/accessibility.aconfig
index d467be6..814c620 100644
--- a/core/java/android/window/flags/accessibility.aconfig
+++ b/core/java/android/window/flags/accessibility.aconfig
@@ -5,4 +5,11 @@
   namespace: "accessibility"
   description: "The flag controls whether the intersection check for non-magnifiable windows is needed when onWindowTransition,"
   bug: "312624253"
+}
+
+flag {
+  name: "magnification_always_draw_fullscreen_border"
+  namespace: "accessibility"
+  description: "Always draw fullscreen orange border in fullscreen magnification"
+  bug: "291891390"
 }
\ No newline at end of file
diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
index 82067de..254f4f7 100644
--- a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
+++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
@@ -77,3 +77,10 @@
   bug: "309593314"
   is_fixed_read_only: true
 }
+
+flag {
+  name: "letterbox_background_wallpaper"
+  namespace: "large_screen_experiences_app_compat"
+  description: "Whether the blurred letterbox wallpaper background is enabled by default"
+  bug: "297195682"
+}
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index 4e86616..63a2474 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -7,3 +7,10 @@
     bug: "320350734"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "enable_desktop_windowing_mode"
+    namespace: "lse_desktop_experience"
+    description: "Enables desktop windowing"
+    bug: "304778354"
+}
diff --git a/core/java/android/window/flags/responsible_apis.aconfig b/core/java/android/window/flags/responsible_apis.aconfig
index 51890ec..94c72c6 100644
--- a/core/java/android/window/flags/responsible_apis.aconfig
+++ b/core/java/android/window/flags/responsible_apis.aconfig
@@ -46,5 +46,5 @@
     name: "bal_respect_app_switch_state_when_check_bound_by_foreground_uid"
     namespace: "responsible_apis"
     description: "Prevent BAL based on it is bound by foreground Uid but the app switch is stopped."
-    bug: "171459802"
+    bug: "283801068"
 }
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 8b3bd97..3f48341 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -81,3 +81,14 @@
     is_fixed_read_only: true
     bug: "321263247"
 }
+
+flag {
+    namespace: "window_surfaces"
+    name: "enable_buffer_transform_hint_from_display"
+    description: "Always use display info to determine VRI's buffer transform hint"
+    is_fixed_read_only: true
+    bug: "301238858"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 86d3037..29669d3 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -96,6 +96,7 @@
 import android.provider.OpenableColumns;
 import android.provider.Settings;
 import android.service.chooser.ChooserTarget;
+import android.service.chooser.Flags;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.HashedStringCache;
@@ -2543,6 +2544,9 @@
 
         @Override
         public boolean isComponentPinned(ComponentName name) {
+            if (Flags.legacyChooserPinningRemoval()) {
+                return false;
+            }
             return mPinnedSharedPrefs.getBoolean(name.flattenToString(), false);
         }
 
@@ -3147,6 +3151,10 @@
     }
 
     private boolean shouldShowTargetDetails(TargetInfo ti) {
+        if (Flags.legacyChooserPinningRemoval()) {
+            // Never show the long press menu if we've removed pinning.
+            return false;
+        }
         ComponentName nearbyShare = getNearbySharingComponent();
         //  Suppress target details for nearby share to hide pin/unpin action
         boolean isNearbyShare = nearbyShare != null && nearbyShare.equals(
diff --git a/core/java/com/android/internal/inputmethod/IImeTracker.aidl b/core/java/com/android/internal/inputmethod/IImeTracker.aidl
index 2759043..b45bc1c 100644
--- a/core/java/com/android/internal/inputmethod/IImeTracker.aidl
+++ b/core/java/com/android/internal/inputmethod/IImeTracker.aidl
@@ -25,28 +25,19 @@
 interface IImeTracker {
 
     /**
-     * Called when an IME show request is created.
+     * Called when an IME request is started.
      *
      * @param tag the logging tag.
-     * @param uid the uid of the client that requested the IME.
-     * @param origin the origin of the IME show request.
-     * @param reason the reason why the IME show request was created.
+     * @param uid the uid of the client that started the request.
+     * @param type the type of the request.
+     * @param origin the origin of the request.
      * @param fromUser whether this request was created directly from user interaction.
-     * @return A new IME tracking token.
-     */
-    ImeTracker.Token onRequestShow(String tag, int uid, int origin, int reason, boolean fromUser);
-
-    /**
-     * Called when an IME hide request is created.
+     * @param reason the reason for starting the request.
      *
-     * @param tag the logging tag.
-     * @param uid the uid of the client that requested the IME.
-     * @param origin the origin of the IME hide request.
-     * @param reason the reason why the IME hide request was created.
-     * @param fromUser whether this request was created directly from user interaction.
-     * @return A new IME tracking token.
+     * @return An IME request tracking token.
      */
-    ImeTracker.Token onRequestHide(String tag, int uid, int origin, int reason, boolean fromUser);
+    ImeTracker.Token onStart(String tag, int uid, int type, int origin, int reason,
+        boolean fromUser);
 
     /**
      * Called when the IME request progresses to a further phase.
diff --git a/core/java/com/android/internal/inputmethod/IInputMethod.aidl b/core/java/com/android/internal/inputmethod/IInputMethod.aidl
index 6abd9e8..2593b78 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethod.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethod.aidl
@@ -71,11 +71,11 @@
 
     void setSessionEnabled(IInputMethodSession session, boolean enabled);
 
-    void showSoftInput(in IBinder showInputToken, in @nullable ImeTracker.Token statsToken,
-            int flags, in ResultReceiver resultReceiver);
+    void showSoftInput(in IBinder showInputToken, in ImeTracker.Token statsToken, int flags,
+            in ResultReceiver resultReceiver);
 
-    void hideSoftInput(in IBinder hideInputToken, in @nullable ImeTracker.Token statsToken,
-            int flags, in ResultReceiver resultReceiver);
+    void hideSoftInput(in IBinder hideInputToken, in ImeTracker.Token statsToken, int flags,
+            in ResultReceiver resultReceiver);
 
     void updateEditorToolType(int toolType);
 
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index 65a2f4b..457b9dd 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -35,15 +35,17 @@
     void setInputMethod(String id, in AndroidFuture future /* T=Void */);
     void setInputMethodAndSubtype(String id, in InputMethodSubtype subtype,
             in AndroidFuture future /* T=Void */);
-    void hideMySoftInput(int flags, int reason, in AndroidFuture future /* T=Void */);
-    void showMySoftInput(int flags, in AndroidFuture future /* T=Void */);
+    void hideMySoftInput(in ImeTracker.Token statsToken, int flags, int reason,
+            in AndroidFuture future /* T=Void */);
+    void showMySoftInput(in ImeTracker.Token statsToken, int flags, int reason,
+            in AndroidFuture future /* T=Void */);
     void updateStatusIconAsync(String packageName, int iconId);
     void switchToPreviousInputMethod(in AndroidFuture future /* T=Boolean */);
     void switchToNextInputMethod(boolean onlyCurrentIme, in AndroidFuture future /* T=Boolean */);
     void shouldOfferSwitchingToNextInputMethod(in AndroidFuture future /* T=Boolean */);
     void notifyUserActionAsync();
     void applyImeVisibilityAsync(IBinder showOrHideInputToken, boolean setVisible,
-            in @nullable ImeTracker.Token statsToken);
+            in ImeTracker.Token statsToken);
     void onStylusHandwritingReady(int requestId, int pid);
     void resetStylusHandwriting(int requestId);
     void switchKeyboardLayoutAsync(int direction);
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index 9b7fa2f..a0aad31 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -189,6 +189,8 @@
      */
     public static String softInputDisplayReasonToString(@SoftInputShowHideReason int reason) {
         switch (reason) {
+            case SoftInputShowHideReason.NOT_SET:
+                return "NOT_SET";
             case SoftInputShowHideReason.SHOW_SOFT_INPUT:
                 return "SHOW_SOFT_INPUT";
             case SoftInputShowHideReason.ATTACH_NEW_INPUT:
@@ -265,6 +267,36 @@
                 return "HIDE_SOFT_INPUT_CLOSE_CURRENT_SESSION";
             case SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_VIEW:
                 return "HIDE_SOFT_INPUT_FROM_VIEW";
+            case SoftInputShowHideReason.SHOW_SOFT_INPUT_LEGACY_DIRECT:
+                return "SHOW_SOFT_INPUT_LEGACY_DIRECT";
+            case SoftInputShowHideReason.HIDE_SOFT_INPUT_LEGACY_DIRECT:
+                return "HIDE_SOFT_INPUT_LEGACY_DIRECT";
+            case SoftInputShowHideReason.SHOW_WINDOW_LEGACY_DIRECT:
+                return "SHOW_WINDOW_LEGACY_DIRECT";
+            case SoftInputShowHideReason.HIDE_WINDOW_LEGACY_DIRECT:
+                return "HIDE_WINDOW_LEGACY_DIRECT";
+            case SoftInputShowHideReason.RESET_NEW_CONFIGURATION:
+                return "RESET_NEW_CONFIGURATION";
+            case SoftInputShowHideReason.UPDATE_CANDIDATES_VIEW_VISIBILITY:
+                return "UPDATE_CANDIDATES_VIEW_VISIBILITY";
+            case SoftInputShowHideReason.CONTROLS_CHANGED:
+                return "CONTROLS_CHANGED";
+            case SoftInputShowHideReason.DISPLAY_CONFIGURATION_CHANGED:
+                return "DISPLAY_CONFIGURATION_CHANGED";
+            case SoftInputShowHideReason.DISPLAY_INSETS_CHANGED:
+                return "DISPLAY_INSETS_CHANGED";
+            case SoftInputShowHideReason.DISPLAY_CONTROLS_CHANGED:
+                return "DISPLAY_CONTROLS_CHANGED";
+            case SoftInputShowHideReason.UNBIND_CURRENT_METHOD:
+                return "UNBIND_CURRENT_METHOD";
+            case SoftInputShowHideReason.HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED:
+                return "HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED";
+            case SoftInputShowHideReason.HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL:
+                return "HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL";
+            case SoftInputShowHideReason.SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT:
+                return "SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT";
+            case SoftInputShowHideReason.SHOW_SOFT_INPUT_IMM_DEPRECATION:
+                return "SHOW_SOFT_INPUT_IMM_DEPRECATION";
             default:
                 return "Unknown=" + reason;
         }
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index 792388d..635a227 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -252,20 +252,21 @@
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#hideMySoftInput(int, int, AndroidFuture)}
-     *
-     * @param reason the reason to hide soft input
+     * Calls {@link IInputMethodPrivilegedOperations#hideMySoftInput}
      */
     @AnyThread
-    public void hideMySoftInput(@InputMethodManager.HideFlags int flags,
-            @SoftInputShowHideReason int reason) {
+    public void hideMySoftInput(@NonNull ImeTracker.Token statsToken,
+            @InputMethodManager.HideFlags int flags, @SoftInputShowHideReason int reason) {
         final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
         if (ops == null) {
+            ImeTracker.forLogging().onFailed(statsToken,
+                    ImeTracker.PHASE_IME_PRIVILEGED_OPERATIONS);
             return;
         }
+        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_PRIVILEGED_OPERATIONS);
         try {
             final AndroidFuture<Void> future = new AndroidFuture<>();
-            ops.hideMySoftInput(flags, reason, future);
+            ops.hideMySoftInput(statsToken, flags, reason, future);
             CompletableFutureUtil.getResult(future);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -273,17 +274,21 @@
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#showMySoftInput(int, AndroidFuture)}
+     * Calls {@link IInputMethodPrivilegedOperations#showMySoftInput}
      */
     @AnyThread
-    public void showMySoftInput(@InputMethodManager.ShowFlags int flags) {
+    public void showMySoftInput(@NonNull ImeTracker.Token statsToken,
+            @InputMethodManager.ShowFlags int flags, @SoftInputShowHideReason int reason) {
         final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
         if (ops == null) {
+            ImeTracker.forLogging().onFailed(statsToken,
+                    ImeTracker.PHASE_IME_PRIVILEGED_OPERATIONS);
             return;
         }
+        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_PRIVILEGED_OPERATIONS);
         try {
             final AndroidFuture<Void> future = new AndroidFuture<>();
-            ops.showMySoftInput(flags, future);
+            ops.showMySoftInput(statsToken, flags, reason, future);
             CompletableFutureUtil.getResult(future);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -379,19 +384,19 @@
      *        {@link android.view.inputmethod.InputMethodManager#hideSoftInputFromWindow(IBinder,
      *        int)}
      * @param setVisible {@code true} to set IME visible, else hidden.
-     * @param statsToken the token tracking the current IME request or {@code null} otherwise.
+     * @param statsToken the token tracking the current IME request.
      */
     @AnyThread
     public void applyImeVisibilityAsync(IBinder showOrHideInputToken, boolean setVisible,
-            @Nullable ImeTracker.Token statsToken) {
+            @NonNull ImeTracker.Token statsToken) {
         final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
         if (ops == null) {
             ImeTracker.forLogging().onFailed(statsToken,
-                    ImeTracker.PHASE_IME_APPLY_VISIBILITY_INSETS_CONSUMER);
+                    ImeTracker.PHASE_IME_PRIVILEGED_OPERATIONS);
             return;
         }
         ImeTracker.forLogging().onProgress(statsToken,
-                ImeTracker.PHASE_IME_APPLY_VISIBILITY_INSETS_CONSUMER);
+                ImeTracker.PHASE_IME_PRIVILEGED_OPERATIONS);
         try {
             ops.applyImeVisibilityAsync(showOrHideInputToken, setVisible, statsToken);
         } catch (RemoteException e) {
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index 861b8a7..da738a0 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -34,6 +34,7 @@
  */
 @Retention(SOURCE)
 @IntDef(value = {
+        SoftInputShowHideReason.NOT_SET,
         SoftInputShowHideReason.SHOW_SOFT_INPUT,
         SoftInputShowHideReason.ATTACH_NEW_INPUT,
         SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME,
@@ -72,8 +73,26 @@
         SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE,
         SoftInputShowHideReason.HIDE_CLOSE_CURRENT_SESSION,
         SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_VIEW,
+        SoftInputShowHideReason.SHOW_SOFT_INPUT_LEGACY_DIRECT,
+        SoftInputShowHideReason.HIDE_SOFT_INPUT_LEGACY_DIRECT,
+        SoftInputShowHideReason.SHOW_WINDOW_LEGACY_DIRECT,
+        SoftInputShowHideReason.HIDE_WINDOW_LEGACY_DIRECT,
+        SoftInputShowHideReason.RESET_NEW_CONFIGURATION,
+        SoftInputShowHideReason.UPDATE_CANDIDATES_VIEW_VISIBILITY,
+        SoftInputShowHideReason.CONTROLS_CHANGED,
+        SoftInputShowHideReason.DISPLAY_CONFIGURATION_CHANGED,
+        SoftInputShowHideReason.DISPLAY_INSETS_CHANGED,
+        SoftInputShowHideReason.DISPLAY_CONTROLS_CHANGED,
+        SoftInputShowHideReason.UNBIND_CURRENT_METHOD,
+        SoftInputShowHideReason.HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED,
+        SoftInputShowHideReason.HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL,
+        SoftInputShowHideReason.SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT,
+        SoftInputShowHideReason.SHOW_SOFT_INPUT_IMM_DEPRECATION,
 })
 public @interface SoftInputShowHideReason {
+    /** Default, undefined reason. */
+    int NOT_SET = ImeProtoEnums.REASON_NOT_SET;
+
     /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */
     int SHOW_SOFT_INPUT = ImeProtoEnums.REASON_SHOW_SOFT_INPUT;
 
@@ -291,4 +310,91 @@
      * Hide soft input when {@link InputMethodManager#hideSoftInputFromView(View, int)} gets called.
      */
     int HIDE_SOFT_INPUT_FROM_VIEW = ImeProtoEnums.REASON_HIDE_SOFT_INPUT_FROM_VIEW;
+
+    /**
+     * Show soft input by legacy (discouraged) call to
+     * {@link android.inputmethodservice.InputMethodService.InputMethodImpl#showSoftInput}.
+     */
+    int SHOW_SOFT_INPUT_LEGACY_DIRECT = ImeProtoEnums.REASON_SHOW_SOFT_INPUT_LEGACY_DIRECT;
+
+    /**
+     * Hide soft input by legacy (discouraged) call to
+     * {@link android.inputmethodservice.InputMethodService.InputMethodImpl#hideSoftInput}.
+     */
+    int HIDE_SOFT_INPUT_LEGACY_DIRECT = ImeProtoEnums.REASON_HIDE_SOFT_INPUT_LEGACY_DIRECT;
+
+    /**
+     * Show soft input by legacy (discouraged) call to
+     * {@link android.inputmethodservice.InputMethodService#showWindow}.
+     */
+    int SHOW_WINDOW_LEGACY_DIRECT = ImeProtoEnums.REASON_SHOW_WINDOW_LEGACY_DIRECT;
+
+    /**
+     * Hide soft input by legacy (discouraged) call to
+     * {@link android.inputmethodservice.InputMethodService#hideWindow}.
+     */
+    int HIDE_WINDOW_LEGACY_DIRECT = ImeProtoEnums.REASON_HIDE_WINDOW_LEGACY_DIRECT;
+
+    /**
+     * Show / Hide soft input by
+     * {@link android.inputmethodservice.InputMethodService#resetStateForNewConfiguration}.
+     */
+    int RESET_NEW_CONFIGURATION = ImeProtoEnums.REASON_RESET_NEW_CONFIGURATION;
+
+    /**
+     * Show / Hide soft input by
+     * {@link android.inputmethodservice.InputMethodService#updateCandidatesVisibility}.
+     */
+    int UPDATE_CANDIDATES_VIEW_VISIBILITY = ImeProtoEnums.REASON_UPDATE_CANDIDATES_VIEW_VISIBILITY;
+
+    /**
+     * Show / Hide soft input by {@link android.view.InsetsController#onControlsChanged}.
+     */
+    int CONTROLS_CHANGED = ImeProtoEnums.REASON_CONTROLS_CHANGED;
+
+    /**
+     * Show soft input by
+     * {@link com.android.wm.shell.common.DisplayImeController#onDisplayConfigurationChanged}.
+     */
+    int DISPLAY_CONFIGURATION_CHANGED = ImeProtoEnums.REASON_DISPLAY_CONFIGURATION_CHANGED;
+
+    /**
+     * Show soft input by
+     * {@link com.android.wm.shell.common.DisplayImeController.PerDisplay#insetsChanged}.
+     */
+    int DISPLAY_INSETS_CHANGED = ImeProtoEnums.REASON_DISPLAY_INSETS_CHANGED;
+
+    /**
+     * Show / Hide soft input by
+     * {@link com.android.wm.shell.common.DisplayImeController.PerDisplay#insetsControlChanged}.
+     */
+    int DISPLAY_CONTROLS_CHANGED = ImeProtoEnums.REASON_DISPLAY_CONTROLS_CHANGED;
+
+    /** Hide soft input by
+     * {@link com.android.server.inputmethod.InputMethodManagerService#onUnbindCurrentMethodByReset}.
+     */
+    int UNBIND_CURRENT_METHOD = ImeProtoEnums.REASON_UNBIND_CURRENT_METHOD;
+
+    /** Hide soft input by {@link android.view.ImeInsetsSourceConsumer#onAnimationStateChanged}. */
+    int HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED =
+            ImeProtoEnums.REASON_HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED;
+
+    /** Hide soft input when we already have a {@link android.view.InsetsSourceControl} by
+     * {@link android.view.ImeInsetsSourceConsumer#requestHide}.
+     */
+    int HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL =
+            ImeProtoEnums.REASON_HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL;
+
+    /**
+     * Show soft input by
+     * {@link android.inputmethodservice.InputMethodService#onToggleSoftInput(int, int)}.
+     */
+    int SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT =
+            ImeProtoEnums.REASON_SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT;
+
+    /**
+     * Show soft input by the deprecated
+     * {@link InputMethodManager#showSoftInputFromInputMethod(IBinder, int)}.
+     */
+    int SHOW_SOFT_INPUT_IMM_DEPRECATION = ImeProtoEnums.REASON_SHOW_SOFT_INPUT_IMM_DEPRECATION;
 }
diff --git a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
index 73df5e8..5e89d06 100644
--- a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
@@ -421,6 +421,8 @@
     @NonNull
     private String[] mUsesStaticLibrariesSorted;
 
+    private boolean mAppMetadataFileInApk = false;
+
     @NonNull
     public static PackageImpl forParsing(@NonNull String packageName, @NonNull String baseCodePath,
             @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp,
@@ -1063,6 +1065,11 @@
         return memtagMode;
     }
 
+    @Override
+    public boolean isAppMetadataFileInApk() {
+        return mAppMetadataFileInApk;
+    }
+
     @Nullable
     @Override
     public Bundle getMetaData() {
@@ -2151,6 +2158,12 @@
     }
 
     @Override
+    public PackageImpl setAppMetadataFileInApk(boolean fileInApk) {
+        mAppMetadataFileInApk = fileInApk;
+        return this;
+    }
+
+    @Override
     public PackageImpl setMetaData(@Nullable Bundle value) {
         metaData = value;
         return this;
@@ -3264,6 +3277,7 @@
         dest.writeLong(this.mBooleans);
         dest.writeLong(this.mBooleans2);
         dest.writeBoolean(this.mAllowCrossUidActivitySwitchFromBelow);
+        dest.writeBoolean(this.mAppMetadataFileInApk);
     }
 
     public PackageImpl(Parcel in) {
@@ -3426,6 +3440,7 @@
         this.mBooleans = in.readLong();
         this.mBooleans2 = in.readLong();
         this.mAllowCrossUidActivitySwitchFromBelow = in.readBoolean();
+        this.mAppMetadataFileInApk = in.readBoolean();
 
         assignDerivedFields();
         assignDerivedFields2();
diff --git a/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java b/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java
index 66cfb69..3c26a7c 100644
--- a/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java
@@ -127,4 +127,7 @@
     ParsedPackage setDirectBootAware(boolean directBootAware);
 
     ParsedPackage setPersistent(boolean persistent);
+
+    /** Retrieves whether the apk contains a app metadata file. */
+    boolean isAppMetadataFileInApk();
 }
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
index 5d185af..5ab17a6 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
@@ -133,6 +133,9 @@
             @Nullable SparseArray<int[]> splitDependencies
     );
 
+    /** Sets whether the apk contains a app metadata file. */
+    ParsingPackage setAppMetadataFileInApk(boolean fileInApk);
+
     ParsingPackage setMetaData(Bundle metaData);
 
     ParsingPackage setForceQueryable(boolean forceQueryable);
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index 2e6053d..95ecd47 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -46,6 +46,7 @@
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.FeatureGroupInfo;
 import android.content.pm.FeatureInfo;
+import android.content.pm.Flags;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.Property;
@@ -133,6 +134,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.security.PublicKey;
@@ -163,6 +165,8 @@
      */
     public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
 
+    public static final String APP_METADATA_FILE_NAME = "app.metadata";
+
     /**
      * Path prefix for apps on expanded storage
      */
@@ -636,6 +640,12 @@
                 pkg.setSigningDetails(SigningDetails.UNKNOWN);
             }
 
+            if (Flags.aslInApkAppMetadataSource()) {
+                try (InputStream in = assets.open(APP_METADATA_FILE_NAME)) {
+                    pkg.setAppMetadataFileInApk(true);
+                } catch (Exception e) { }
+            }
+
             return input.success(pkg);
         } catch (Exception e) {
             return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
@@ -686,7 +696,8 @@
      */
     private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
             String codePath, Resources res, XmlResourceParser parser, int flags,
-            boolean shouldSkipComponents) throws XmlPullParserException, IOException {
+            boolean shouldSkipComponents)
+            throws XmlPullParserException, IOException {
         final String splitName;
         final String pkgName;
 
diff --git a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java b/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java
similarity index 81%
rename from core/java/com/android/internal/protolog/BaseProtoLogImpl.java
rename to core/java/com/android/internal/protolog/LegacyProtoLogImpl.java
index abe6c7c..30de546 100644
--- a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -37,8 +37,11 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ILogger;
+import com.android.internal.protolog.common.IProtoLog;
 import com.android.internal.protolog.common.IProtoLogGroup;
 import com.android.internal.protolog.common.LogDataType;
+import com.android.internal.protolog.common.LogLevel;
 import com.android.internal.util.TraceBuffer;
 
 import java.io.File;
@@ -48,52 +51,49 @@
 import java.util.TreeMap;
 import java.util.stream.Collectors;
 
-
 /**
  * A service for the ProtoLog logging system.
  */
-public class BaseProtoLogImpl {
-    protected static final TreeMap<String, IProtoLogGroup> LOG_GROUPS = new TreeMap<>();
+public class LegacyProtoLogImpl implements IProtoLog {
+    private final TreeMap<String, IProtoLogGroup> mLogGroups = new TreeMap<>();
 
-    /**
-     * A runnable to update the cached output of {@link #isEnabled}.
-     *
-     * Must be invoked after every action that could change the result of {@link #isEnabled}, eg.
-     * starting / stopping proto log, or enabling / disabling log groups.
-     */
-    public static Runnable sCacheUpdater = () -> { };
-
-    protected static void addLogGroupEnum(IProtoLogGroup[] config) {
-        for (IProtoLogGroup group : config) {
-            LOG_GROUPS.put(group.name(), group);
-        }
-    }
-
+    private static final int BUFFER_CAPACITY = 1024 * 1024;
+    private static final int PER_CHUNK_SIZE = 1024;
     private static final String TAG = "ProtoLog";
     private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
-    static final String PROTOLOG_VERSION = "1.0.0";
+    static final String PROTOLOG_VERSION = "2.0.0";
     private static final int DEFAULT_PER_CHUNK_SIZE = 0;
 
     private final File mLogFile;
-    private final String mViewerConfigFilename;
+    private final String mLegacyViewerConfigFilename;
     private final TraceBuffer mBuffer;
-    protected final ProtoLogViewerConfigReader mViewerConfig;
+    private final LegacyProtoLogViewerConfigReader mViewerConfig;
     private final int mPerChunkSize;
 
     private boolean mProtoLogEnabled;
     private boolean mProtoLogEnabledLockFree;
     private final Object mProtoLogEnabledLock = new Object();
 
-    @VisibleForTesting
-    public enum LogLevel {
-        DEBUG, VERBOSE, INFO, WARN, ERROR, WTF
+    public LegacyProtoLogImpl(String outputFile, String viewerConfigFilename) {
+        this(new File(outputFile), viewerConfigFilename, BUFFER_CAPACITY,
+                new LegacyProtoLogViewerConfigReader(), PER_CHUNK_SIZE);
+    }
+
+    public LegacyProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity,
+            LegacyProtoLogViewerConfigReader viewerConfig, int perChunkSize) {
+        mLogFile = file;
+        mBuffer = new TraceBuffer(bufferCapacity);
+        mLegacyViewerConfigFilename = viewerConfigFilename;
+        mViewerConfig = viewerConfig;
+        mPerChunkSize = perChunkSize;
     }
 
     /**
      * Main log method, do not call directly.
      */
     @VisibleForTesting
-    public void log(LogLevel level, IProtoLogGroup group, int messageHash, int paramsMask,
+    @Override
+    public void log(LogLevel level, IProtoLogGroup group, long messageHash, int paramsMask,
             @Nullable String messageString, Object[] args) {
         if (group.isLogToProto()) {
             logToProto(messageHash, paramsMask, args);
@@ -103,7 +103,7 @@
         }
     }
 
-    private void logToLogcat(String tag, LogLevel level, int messageHash,
+    private void logToLogcat(String tag, LogLevel level, long messageHash,
             @Nullable String messageString, Object[] args) {
         String message = null;
         if (messageString == null) {
@@ -157,7 +157,7 @@
         }
     }
 
-    private void logToProto(int messageHash, int paramsMask, Object[] args) {
+    private void logToProto(long messageHash, int paramsMask, Object[] args) {
         if (!isProtoEnabled()) {
             return;
         }
@@ -219,20 +219,6 @@
         }
     }
 
-    public BaseProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity,
-            ProtoLogViewerConfigReader viewerConfig) {
-        this(file, viewerConfigFilename, bufferCapacity, viewerConfig, DEFAULT_PER_CHUNK_SIZE);
-    }
-
-    public BaseProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity,
-            ProtoLogViewerConfigReader viewerConfig, int perChunkSize) {
-        mLogFile = file;
-        mBuffer = new TraceBuffer(bufferCapacity);
-        mViewerConfigFilename = viewerConfigFilename;
-        mViewerConfig = viewerConfig;
-        mPerChunkSize = perChunkSize;
-    }
-
     /**
      * Starts the logging a circular proto buffer.
      *
@@ -248,7 +234,6 @@
             mProtoLogEnabled = true;
             mProtoLogEnabledLockFree = true;
         }
-        sCacheUpdater.run();
     }
 
     /**
@@ -274,7 +259,6 @@
                 throw new IllegalStateException("logging enabled while waiting for flush.");
             }
         }
-        sCacheUpdater.run();
     }
 
     /**
@@ -284,11 +268,11 @@
         return mProtoLogEnabledLockFree;
     }
 
-    protected int setLogging(boolean setTextLogging, boolean value, PrintWriter pw,
+    private int setLogging(boolean setTextLogging, boolean value, ILogger logger,
             String... groups) {
         for (int i = 0; i < groups.length; i++) {
             String group = groups[i];
-            IProtoLogGroup g = LOG_GROUPS.get(group);
+            IProtoLogGroup g = mLogGroups.get(group);
             if (g != null) {
                 if (setTextLogging) {
                     g.setLogToLogcat(value);
@@ -296,11 +280,10 @@
                     g.setLogToProto(value);
                 }
             } else {
-                logAndPrintln(pw, "No IProtoLogGroup named " + group);
+                logger.log("No IProtoLogGroup named " + group);
                 return -1;
             }
         }
-        sCacheUpdater.run();
         return 0;
     }
 
@@ -330,6 +313,7 @@
         while ((arg = shell.getNextArg()) != null) {
             args.add(arg);
         }
+        final ILogger logger = (msg) -> logAndPrintln(pw, msg);
         String[] groups = args.toArray(new String[args.size()]);
         switch (cmd) {
             case "start":
@@ -342,14 +326,14 @@
                 logAndPrintln(pw, getStatus());
                 return 0;
             case "enable":
-                return setLogging(false, true, pw, groups);
+                return setLogging(false, true, logger, groups);
             case "enable-text":
-                mViewerConfig.loadViewerConfig(pw, mViewerConfigFilename);
-                return setLogging(true, true, pw, groups);
+                mViewerConfig.loadViewerConfig(logger, mLegacyViewerConfigFilename);
+                return setLogging(true, true, logger, groups);
             case "disable":
-                return setLogging(false, false, pw, groups);
+                return setLogging(false, false, logger, groups);
             case "disable-text":
-                return setLogging(true, false, pw, groups);
+                return setLogging(true, false, logger, groups);
             default:
                 return unknownCommand(pw);
         }
@@ -362,12 +346,12 @@
         return "ProtoLog status: "
                 + ((isProtoEnabled()) ? "Enabled" : "Disabled")
                 + "\nEnabled log groups: \n  Proto: "
-                + LOG_GROUPS.values().stream().filter(
-                    it -> it.isEnabled() && it.isLogToProto())
+                + mLogGroups.values().stream().filter(
+                        it -> it.isEnabled() && it.isLogToProto())
                 .map(IProtoLogGroup::name).collect(Collectors.joining(" "))
                 + "\n  Logcat: "
-                + LOG_GROUPS.values().stream().filter(
-                    it -> it.isEnabled() && it.isLogToLogcat())
+                + mLogGroups.values().stream().filter(
+                        it -> it.isEnabled() && it.isLogToLogcat())
                 .map(IProtoLogGroup::name).collect(Collectors.joining(" "))
                 + "\nLogging definitions loaded: " + mViewerConfig.knownViewerStringsNumber();
     }
@@ -393,5 +377,26 @@
             pw.flush();
         }
     }
+
+    /**
+     * Start text logging
+     * @param groups Groups to start text logging for
+     * @param logger A logger to write status updates to
+     * @return status code
+     */
+    public int startLoggingToLogcat(String[] groups, ILogger logger) {
+        mViewerConfig.loadViewerConfig(logger, mLegacyViewerConfigFilename);
+        return setLogging(true /* setTextLogging */, true, logger, groups);
+    }
+
+    /**
+     * Stop text logging
+     * @param groups Groups to start text logging for
+     * @param logger A logger to write status updates to
+     * @return status code
+     */
+    public int stopLoggingToLogcat(String[] groups, ILogger logger) {
+        return setLogging(true /* setTextLogging */, false, logger, groups);
+    }
 }
 
diff --git a/core/java/com/android/internal/protolog/LegacyProtoLogViewerConfigReader.java b/core/java/com/android/internal/protolog/LegacyProtoLogViewerConfigReader.java
new file mode 100644
index 0000000..1833410
--- /dev/null
+++ b/core/java/com/android/internal/protolog/LegacyProtoLogViewerConfigReader.java
@@ -0,0 +1,117 @@
+/*
+ * 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.internal.protolog;
+
+import com.android.internal.protolog.common.ILogger;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.zip.GZIPInputStream;
+
+/**
+ * Handles loading and parsing of ProtoLog viewer configuration.
+ */
+public class LegacyProtoLogViewerConfigReader {
+
+    private static final String TAG = "ProtoLogViewerConfigReader";
+    private Map<Long, String> mLogMessageMap = null;
+
+    /** Returns message format string for its hash or null if unavailable. */
+    public synchronized String getViewerString(long messageHash) {
+        if (mLogMessageMap != null) {
+            return mLogMessageMap.get(messageHash);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Reads the specified viewer configuration file. Does nothing if the config is already loaded.
+     */
+    public synchronized void loadViewerConfig(ILogger logger, String viewerConfigFilename) {
+        try {
+            loadViewerConfig(new GZIPInputStream(new FileInputStream(viewerConfigFilename)));
+            logger.log("Loaded " + mLogMessageMap.size()
+                    + " log definitions from " + viewerConfigFilename);
+        } catch (FileNotFoundException e) {
+            logger.log("Unable to load log definitions: File "
+                    + viewerConfigFilename + " not found." + e);
+        } catch (IOException e) {
+            logger.log("Unable to load log definitions: IOException while reading "
+                    + viewerConfigFilename + ". " + e);
+        } catch (JSONException e) {
+            logger.log("Unable to load log definitions: JSON parsing exception while reading "
+                    + viewerConfigFilename + ". " + e);
+        }
+    }
+
+    /**
+     * Reads the specified viewer configuration input stream.
+     * Does nothing if the config is already loaded.
+     */
+    public synchronized void loadViewerConfig(InputStream viewerConfigInputStream)
+            throws IOException, JSONException {
+        if (mLogMessageMap != null) {
+            return;
+        }
+        InputStreamReader config = new InputStreamReader(viewerConfigInputStream);
+        BufferedReader reader = new BufferedReader(config);
+        StringBuilder builder = new StringBuilder();
+        String line;
+        while ((line = reader.readLine()) != null) {
+            builder.append(line).append('\n');
+        }
+        reader.close();
+        JSONObject json = new JSONObject(builder.toString());
+        JSONObject messages = json.getJSONObject("messages");
+
+        mLogMessageMap = new TreeMap<>();
+        Iterator it = messages.keys();
+        while (it.hasNext()) {
+            String key = (String) it.next();
+            try {
+                long hash = Long.parseLong(key);
+                JSONObject val = messages.getJSONObject(key);
+                String msg = val.getString("message");
+                mLogMessageMap.put(hash, msg);
+            } catch (NumberFormatException expected) {
+                // Not a messageHash - skip it
+            }
+        }
+    }
+
+    /**
+     * Returns the number of loaded log definitions kept in memory.
+     */
+    public synchronized int knownViewerStringsNumber() {
+        if (mLogMessageMap != null) {
+            return mLogMessageMap.size();
+        }
+        return 0;
+    }
+
+}
diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
new file mode 100644
index 0000000..53062d8
--- /dev/null
+++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
@@ -0,0 +1,559 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.protolog;
+
+import static perfetto.protos.PerfettoTrace.InternedData.PROTOLOG_STACKTRACE;
+import static perfetto.protos.PerfettoTrace.InternedData.PROTOLOG_STRING_ARGS;
+import static perfetto.protos.PerfettoTrace.InternedString.IID;
+import static perfetto.protos.PerfettoTrace.InternedString.STR;
+import static perfetto.protos.PerfettoTrace.ProtoLogMessage.BOOLEAN_PARAMS;
+import static perfetto.protos.PerfettoTrace.ProtoLogMessage.DOUBLE_PARAMS;
+import static perfetto.protos.PerfettoTrace.ProtoLogMessage.STACKTRACE_IID;
+import static perfetto.protos.PerfettoTrace.ProtoLogMessage.MESSAGE_ID;
+import static perfetto.protos.PerfettoTrace.ProtoLogMessage.SINT64_PARAMS;
+import static perfetto.protos.PerfettoTrace.ProtoLogMessage.STR_PARAM_IIDS;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.GROUPS;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.Group.ID;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.Group.NAME;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.Group.TAG;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MESSAGES;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData.GROUP_ID;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData.LEVEL;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData.MESSAGE;
+import static perfetto.protos.PerfettoTrace.TracePacket.INTERNED_DATA;
+import static perfetto.protos.PerfettoTrace.TracePacket.PROTOLOG_MESSAGE;
+import static perfetto.protos.PerfettoTrace.TracePacket.PROTOLOG_VIEWER_CONFIG;
+import static perfetto.protos.PerfettoTrace.TracePacket.SEQUENCE_FLAGS;
+import static perfetto.protos.PerfettoTrace.TracePacket.SEQ_INCREMENTAL_STATE_CLEARED;
+import static perfetto.protos.PerfettoTrace.TracePacket.SEQ_NEEDS_INCREMENTAL_STATE;
+import static perfetto.protos.PerfettoTrace.TracePacket.TIMESTAMP;
+
+import android.annotation.Nullable;
+import android.os.ShellCommand;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.text.TextUtils;
+import android.tracing.perfetto.DataSourceParams;
+import android.tracing.perfetto.InitArguments;
+import android.tracing.perfetto.Producer;
+import android.tracing.perfetto.TracingContext;
+import android.util.LongArray;
+import android.util.Slog;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ILogger;
+import com.android.internal.protolog.common.IProtoLog;
+import com.android.internal.protolog.common.IProtoLogGroup;
+import com.android.internal.protolog.common.LogDataType;
+import com.android.internal.protolog.common.LogLevel;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData;
+
+/**
+ * A service for the ProtoLog logging system.
+ */
+public class PerfettoProtoLogImpl implements IProtoLog {
+    private final TreeMap<String, IProtoLogGroup> mLogGroups = new TreeMap<>();
+    private static final String LOG_TAG = "ProtoLog";
+    private final AtomicInteger mTracingInstances = new AtomicInteger();
+
+    private final ProtoLogDataSource mDataSource = new ProtoLogDataSource(
+            this.mTracingInstances::incrementAndGet,
+            this::dumpTransitionTraceConfig,
+            this.mTracingInstances::decrementAndGet
+    );
+    private final ProtoLogViewerConfigReader mViewerConfigReader;
+    private final ViewerConfigInputStreamProvider mViewerConfigInputStreamProvider;
+
+    public PerfettoProtoLogImpl(String viewerConfigFilePath) {
+        this(() -> {
+            try {
+                return new ProtoInputStream(new FileInputStream(viewerConfigFilePath));
+            } catch (FileNotFoundException e) {
+                Slog.w(LOG_TAG, "Failed to load viewer config file " + viewerConfigFilePath, e);
+                return null;
+            }
+        });
+    }
+
+    public PerfettoProtoLogImpl(ViewerConfigInputStreamProvider viewerConfigInputStreamProvider) {
+        this(viewerConfigInputStreamProvider,
+                new ProtoLogViewerConfigReader(viewerConfigInputStreamProvider));
+    }
+
+    @VisibleForTesting
+    public PerfettoProtoLogImpl(
+            ViewerConfigInputStreamProvider viewerConfigInputStreamProvider,
+            ProtoLogViewerConfigReader viewerConfigReader
+    ) {
+        Producer.init(InitArguments.DEFAULTS);
+        mDataSource.register(DataSourceParams.DEFAULTS);
+        this.mViewerConfigInputStreamProvider = viewerConfigInputStreamProvider;
+        this.mViewerConfigReader = viewerConfigReader;
+    }
+
+    /**
+     * Main log method, do not call directly.
+     */
+    @VisibleForTesting
+    @Override
+    public void log(LogLevel level, IProtoLogGroup group, long messageHash, int paramsMask,
+            @Nullable String messageString, Object[] args) {
+        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "log");
+
+        long tsNanos = SystemClock.elapsedRealtimeNanos();
+        try {
+            logToProto(level, group.name(), messageHash, paramsMask, args, tsNanos);
+            if (group.isLogToLogcat()) {
+                logToLogcat(group.getTag(), level, messageHash, messageString, args);
+            }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+        }
+    }
+
+    private void dumpTransitionTraceConfig() {
+        ProtoInputStream pis = mViewerConfigInputStreamProvider.getInputStream();
+
+        if (pis == null) {
+            Slog.w(LOG_TAG, "Failed to get viewer input stream.");
+            return;
+        }
+
+        mDataSource.trace(ctx -> {
+            final ProtoOutputStream os = ctx.newTracePacket();
+
+            os.write(TIMESTAMP, SystemClock.elapsedRealtimeNanos());
+
+            final long outProtologViewerConfigToken = os.start(PROTOLOG_VIEWER_CONFIG);
+            while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                if (pis.getFieldNumber() == (int) MESSAGES) {
+                    final long inMessageToken = pis.start(MESSAGES);
+                    final long outMessagesToken = os.start(MESSAGES);
+
+                    while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                        switch (pis.getFieldNumber()) {
+                            case (int) MessageData.MESSAGE_ID:
+                                os.write(MessageData.MESSAGE_ID,
+                                        pis.readLong(MessageData.MESSAGE_ID));
+                                break;
+                            case (int) MESSAGE:
+                                os.write(MESSAGE, pis.readString(MESSAGE));
+                                break;
+                            case (int) LEVEL:
+                                os.write(LEVEL, pis.readInt(LEVEL));
+                                break;
+                            case (int) GROUP_ID:
+                                os.write(GROUP_ID, pis.readInt(GROUP_ID));
+                                break;
+                            default:
+                                throw new RuntimeException(
+                                        "Unexpected field id " + pis.getFieldNumber());
+                        }
+                    }
+
+                    pis.end(inMessageToken);
+                    os.end(outMessagesToken);
+                }
+
+                if (pis.getFieldNumber() == (int) GROUPS) {
+                    final long inGroupToken = pis.start(GROUPS);
+                    final long outGroupToken = os.start(GROUPS);
+
+                    while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                        switch (pis.getFieldNumber()) {
+                            case (int) ID:
+                                int id = pis.readInt(ID);
+                                os.write(ID, id);
+                                break;
+                            case (int) NAME:
+                                String name = pis.readString(NAME);
+                                os.write(NAME, name);
+                                break;
+                            case (int) TAG:
+                                String tag = pis.readString(TAG);
+                                os.write(TAG, tag);
+                                break;
+                            default:
+                                throw new RuntimeException(
+                                        "Unexpected field id " + pis.getFieldNumber());
+                        }
+                    }
+
+                    pis.end(inGroupToken);
+                    os.end(outGroupToken);
+                }
+            }
+
+            os.end(outProtologViewerConfigToken);
+
+            ctx.flush();
+        });
+
+        mDataSource.flush();
+    }
+
+    private void logToLogcat(String tag, LogLevel level, long messageHash,
+            @Nullable String messageString, Object[] args) {
+        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "logToLogcat");
+        try {
+            doLogToLogcat(tag, level, messageHash, messageString, args);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+        }
+    }
+
+    private void doLogToLogcat(String tag, LogLevel level, long messageHash,
+            @androidx.annotation.Nullable String messageString, Object[] args) {
+        String message = null;
+        if (messageString == null) {
+            messageString = mViewerConfigReader.getViewerString(messageHash);
+        }
+        if (messageString != null) {
+            if (args != null) {
+                try {
+                    message = TextUtils.formatSimple(messageString, args);
+                } catch (Exception ex) {
+                    Slog.w(LOG_TAG, "Invalid ProtoLog format string.", ex);
+                }
+            } else {
+                message = messageString;
+            }
+        }
+        if (message == null) {
+            StringBuilder builder = new StringBuilder("UNKNOWN MESSAGE (" + messageHash + ")");
+            for (Object o : args) {
+                builder.append(" ").append(o);
+            }
+            message = builder.toString();
+        }
+        passToLogcat(tag, level, message);
+    }
+
+    /**
+     * SLog wrapper.
+     */
+    @VisibleForTesting
+    public void passToLogcat(String tag, LogLevel level, String message) {
+        switch (level) {
+            case DEBUG:
+                Slog.d(tag, message);
+                break;
+            case VERBOSE:
+                Slog.v(tag, message);
+                break;
+            case INFO:
+                Slog.i(tag, message);
+                break;
+            case WARN:
+                Slog.w(tag, message);
+                break;
+            case ERROR:
+                Slog.e(tag, message);
+                break;
+            case WTF:
+                Slog.wtf(tag, message);
+                break;
+        }
+    }
+
+    private void logToProto(LogLevel level, String groupName, long messageHash, int paramsMask,
+            Object[] args, long tsNanos) {
+        if (!isProtoEnabled()) {
+            return;
+        }
+
+        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "logToProto");
+        try {
+            doLogToProto(level, groupName, messageHash, paramsMask, args, tsNanos);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+        }
+    }
+
+    private void doLogToProto(LogLevel level, String groupName, long messageHash, int paramsMask,
+            Object[] args, long tsNanos) {
+        mDataSource.trace(ctx -> {
+            final ProtoLogDataSource.TlsState tlsState = ctx.getCustomTlsState();
+            final LogLevel logFrom = tlsState.getLogFromLevel(groupName);
+
+            if (level.ordinal() < logFrom.ordinal()) {
+                return;
+            }
+
+            if (args != null) {
+                // Intern all string params before creating the trace packet for the proto
+                // message so that the interned strings appear before in the trace to make the
+                // trace processing easier.
+                int argIndex = 0;
+                for (Object o : args) {
+                    int type = LogDataType.bitmaskToLogDataType(paramsMask, argIndex);
+                    if (type == LogDataType.STRING) {
+                        internStringArg(ctx, o.toString());
+                    }
+                    argIndex++;
+                }
+            }
+
+            int internedStacktrace = 0;
+            if (tlsState.getShouldCollectStacktrace(groupName)) {
+                // Intern stackstraces before creating the trace packet for the proto message so
+                // that the interned stacktrace strings appear before in the trace to make the
+                // trace processing easier.
+                String stacktrace = collectStackTrace();
+                internedStacktrace = internStacktraceString(ctx, stacktrace);
+            }
+
+            final ProtoOutputStream os = ctx.newTracePacket();
+            os.write(TIMESTAMP, tsNanos);
+            long token = os.start(PROTOLOG_MESSAGE);
+            os.write(MESSAGE_ID, messageHash);
+
+            boolean needsIncrementalState = false;
+
+            if (args != null) {
+
+                int argIndex = 0;
+                LongArray longParams = new LongArray();
+                ArrayList<Double> doubleParams = new ArrayList<>();
+                ArrayList<Boolean> booleanParams = new ArrayList<>();
+                for (Object o : args) {
+                    int type = LogDataType.bitmaskToLogDataType(paramsMask, argIndex);
+                    try {
+                        switch (type) {
+                            case LogDataType.STRING:
+                                final int internedStringId = internStringArg(ctx, o.toString());
+                                os.write(STR_PARAM_IIDS, internedStringId);
+                                needsIncrementalState = true;
+                                break;
+                            case LogDataType.LONG:
+                                longParams.add(((Number) o).longValue());
+                                break;
+                            case LogDataType.DOUBLE:
+                                doubleParams.add(((Number) o).doubleValue());
+                                break;
+                            case LogDataType.BOOLEAN:
+                                booleanParams.add((boolean) o);
+                                break;
+                        }
+                    } catch (ClassCastException ex) {
+                        Slog.e(LOG_TAG, "Invalid ProtoLog paramsMask", ex);
+                    }
+                    argIndex++;
+                }
+
+                for (int i = 0; i < longParams.size(); ++i) {
+                    os.write(SINT64_PARAMS, longParams.get(i));
+                }
+                doubleParams.forEach(it -> os.write(DOUBLE_PARAMS, it));
+                // Converting booleans to int because Perfetto doesn't yet support repeated
+                // booleans, so we use a repeated integers instead (b/313651412).
+                booleanParams.forEach(it -> os.write(BOOLEAN_PARAMS, it ? 1 : 0));
+            }
+
+            if (tlsState.getShouldCollectStacktrace(groupName)) {
+                os.write(STACKTRACE_IID, internedStacktrace);
+            }
+
+            os.end(token);
+
+            if (needsIncrementalState) {
+                os.write(SEQUENCE_FLAGS, SEQ_NEEDS_INCREMENTAL_STATE);
+            }
+
+        });
+    }
+
+    private static final int STACK_SIZE_TO_PROTO_LOG_ENTRY_CALL = 12;
+
+    private String collectStackTrace() {
+        StackTraceElement[] stackTrace =  Thread.currentThread().getStackTrace();
+        StringWriter sw = new StringWriter();
+        try (PrintWriter pw = new PrintWriter(sw)) {
+            for (int i = STACK_SIZE_TO_PROTO_LOG_ENTRY_CALL; i < stackTrace.length; ++i) {
+                pw.println("\tat " + stackTrace[i]);
+            }
+        }
+
+        return sw.toString();
+    }
+
+    private int internStacktraceString(TracingContext<ProtoLogDataSource.Instance,
+            ProtoLogDataSource.TlsState,
+            ProtoLogDataSource.IncrementalState> ctx,
+            String stacktrace) {
+        final ProtoLogDataSource.IncrementalState incrementalState = ctx.getIncrementalState();
+        return internString(ctx, incrementalState.stacktraceInterningMap,
+                PROTOLOG_STACKTRACE, stacktrace);
+    }
+
+    private int internStringArg(
+            TracingContext<ProtoLogDataSource.Instance,
+            ProtoLogDataSource.TlsState,
+            ProtoLogDataSource.IncrementalState> ctx,
+            String string
+    ) {
+        final ProtoLogDataSource.IncrementalState incrementalState = ctx.getIncrementalState();
+        return internString(ctx, incrementalState.argumentInterningMap,
+                PROTOLOG_STRING_ARGS, string);
+    }
+
+    private int internString(
+            TracingContext<ProtoLogDataSource.Instance,
+                ProtoLogDataSource.TlsState,
+                ProtoLogDataSource.IncrementalState> ctx,
+            Map<String, Integer> internMap,
+            long fieldId,
+            String string
+    ) {
+        final ProtoLogDataSource.IncrementalState incrementalState = ctx.getIncrementalState();
+
+        if (!incrementalState.clearReported) {
+            final ProtoOutputStream os = ctx.newTracePacket();
+            os.write(SEQUENCE_FLAGS, SEQ_INCREMENTAL_STATE_CLEARED);
+            incrementalState.clearReported = true;
+        }
+
+        if (!internMap.containsKey(string)) {
+            final int internedIndex = internMap.size() + 1;
+            internMap.put(string, internedIndex);
+
+            final ProtoOutputStream os = ctx.newTracePacket();
+            final long token = os.start(INTERNED_DATA);
+            final long innerToken = os.start(fieldId);
+            os.write(IID, internedIndex);
+            os.write(STR, string.getBytes());
+            os.end(innerToken);
+            os.end(token);
+        }
+
+        return internMap.get(string);
+    }
+
+    /**
+     * Responds to a shell command.
+     */
+    public int onShellCommand(ShellCommand shell) {
+        PrintWriter pw = shell.getOutPrintWriter();
+        String cmd = shell.getNextArg();
+        if (cmd == null) {
+            return unknownCommand(pw);
+        }
+        ArrayList<String> args = new ArrayList<>();
+        String arg;
+        while ((arg = shell.getNextArg()) != null) {
+            args.add(arg);
+        }
+        final ILogger logger = (msg) -> logAndPrintln(pw, msg);
+        String[] groups = args.toArray(new String[args.size()]);
+        switch (cmd) {
+            case "enable-text":
+                return this.startLoggingToLogcat(groups, logger);
+            case "disable-text":
+                return this.stopLoggingToLogcat(groups, logger);
+            default:
+                return unknownCommand(pw);
+        }
+    }
+
+    private int unknownCommand(PrintWriter pw) {
+        pw.println("Unknown command");
+        pw.println("Window manager logging options:");
+        pw.println("  enable-text [group...]: Enable logcat logging for given groups");
+        pw.println("  disable-text [group...]: Disable logcat logging for given groups");
+        return -1;
+    }
+
+    /**
+     * Returns {@code true} iff logging to proto is enabled.
+     */
+    public boolean isProtoEnabled() {
+        return mTracingInstances.get() > 0;
+    }
+
+    /**
+     * Start text logging
+     * @param groups Groups to start text logging for
+     * @param logger A logger to write status updates to
+     * @return status code
+     */
+    public int startLoggingToLogcat(String[] groups, ILogger logger) {
+        mViewerConfigReader.loadViewerConfig(logger);
+        return setTextLogging(true, logger, groups);
+    }
+
+    /**
+     * Stop text logging
+     * @param groups Groups to start text logging for
+     * @param logger A logger to write status updates to
+     * @return status code
+     */
+    public int stopLoggingToLogcat(String[] groups, ILogger logger) {
+        mViewerConfigReader.unloadViewerConfig();
+        return setTextLogging(false, logger, groups);
+    }
+
+    /**
+     * Start logging the stack trace of the when the log message happened for target groups
+     * @return status code
+     */
+    public int startLoggingStackTrace(String[] groups, ILogger logger) {
+        return -1;
+    }
+
+    /**
+     * Stop logging the stack trace of the when the log message happened for target groups
+     * @return status code
+     */
+    public int stopLoggingStackTrace() {
+        return -1;
+    }
+
+    private int setTextLogging(boolean value, ILogger logger, String... groups) {
+        for (int i = 0; i < groups.length; i++) {
+            String group = groups[i];
+            IProtoLogGroup g = mLogGroups.get(group);
+            if (g != null) {
+                g.setLogToLogcat(value);
+            } else {
+                logger.log("No IProtoLogGroup named " + group);
+                return -1;
+            }
+        }
+        return 0;
+    }
+
+    static void logAndPrintln(@Nullable PrintWriter pw, String msg) {
+        Slog.i(LOG_TAG, msg);
+        if (pw != null) {
+            pw.println(msg);
+            pw.flush();
+        }
+    }
+}
+
diff --git a/core/java/com/android/internal/protolog/ProtoLogDataSource.java b/core/java/com/android/internal/protolog/ProtoLogDataSource.java
new file mode 100644
index 0000000..a8ff75d
--- /dev/null
+++ b/core/java/com/android/internal/protolog/ProtoLogDataSource.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.protolog;
+
+import static perfetto.protos.PerfettoTrace.DataSourceConfig.PROTOLOG_CONFIG;
+import static perfetto.protos.PerfettoTrace.ProtoLogConfig.GROUP_OVERRIDES;
+import static perfetto.protos.PerfettoTrace.ProtoLogConfig.TRACING_MODE;
+import static perfetto.protos.PerfettoTrace.ProtoLogGroup.COLLECT_STACKTRACE;
+import static perfetto.protos.PerfettoTrace.ProtoLogGroup.LOG_FROM;
+import static perfetto.protos.PerfettoTrace.ProtoLogGroup.GROUP_NAME;
+
+import android.tracing.perfetto.CreateIncrementalStateArgs;
+import android.tracing.perfetto.CreateTlsStateArgs;
+import android.tracing.perfetto.DataSource;
+import android.tracing.perfetto.DataSourceInstance;
+import android.tracing.perfetto.FlushCallbackArguments;
+import android.tracing.perfetto.StartCallbackArguments;
+import android.tracing.perfetto.StopCallbackArguments;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.internal.protolog.common.LogLevel;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import perfetto.protos.PerfettoTrace;
+
+public class ProtoLogDataSource extends DataSource<ProtoLogDataSource.Instance,
+        ProtoLogDataSource.TlsState,
+        ProtoLogDataSource.IncrementalState> {
+
+    private final Runnable mOnStart;
+    private final Runnable mOnFlush;
+    private final Runnable mOnStop;
+
+    public ProtoLogDataSource(Runnable onStart, Runnable onFlush, Runnable onStop) {
+        super("android.protolog");
+        this.mOnStart = onStart;
+        this.mOnFlush = onFlush;
+        this.mOnStop = onStop;
+    }
+
+    @Override
+    public Instance createInstance(ProtoInputStream configStream, int instanceIndex) {
+        ProtoLogConfig config = null;
+
+        try {
+            while (configStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                try {
+                    if (configStream.getFieldNumber() == (int) PROTOLOG_CONFIG) {
+                        if (config != null) {
+                            throw new RuntimeException("ProtoLog config already set in loop");
+                        }
+                        config = readProtoLogConfig(configStream);
+                    }
+                } catch (WireTypeMismatchException e) {
+                    throw new RuntimeException("Failed to parse ProtoLog DataSource config", e);
+                }
+            }
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to read ProtoLog DataSource config", e);
+        }
+
+        if (config == null) {
+            // No config found
+            config = ProtoLogConfig.DEFAULT;
+        }
+
+        return new Instance(
+                this, instanceIndex, config, mOnStart, mOnFlush, mOnStop);
+    }
+
+    @Override
+    public TlsState createTlsState(CreateTlsStateArgs<Instance> args) {
+        try (Instance dsInstance = args.getDataSourceInstanceLocked()) {
+            if (dsInstance == null) {
+                // Datasource instance has been removed
+                return new TlsState(ProtoLogConfig.DEFAULT);
+            }
+            return new TlsState(dsInstance.mConfig);
+        }
+    }
+
+    @Override
+    public IncrementalState createIncrementalState(CreateIncrementalStateArgs<Instance> args) {
+        return new IncrementalState();
+    }
+
+    public static class TlsState {
+        private final ProtoLogConfig mConfig;
+
+        private TlsState(ProtoLogConfig config) {
+            this.mConfig = config;
+        }
+
+        /**
+         * Get the log from level for a group.
+         * @param groupTag The tag of the group to get the log from level.
+         * @return The lowest LogLevel (inclusive) to log message from.
+         */
+        public LogLevel getLogFromLevel(String groupTag) {
+            return getConfigFor(groupTag).logFrom;
+        }
+
+        /**
+         * Get if the stacktrace for the log message should be collected for this group.
+         * @param groupTag The tag of the group to get whether or not a stacktrace was requested.
+         * @return True iff a stacktrace was requested to be collected from this group in the
+         *         tracing config.
+         */
+        public boolean getShouldCollectStacktrace(String groupTag) {
+            return getConfigFor(groupTag).collectStackTrace;
+        }
+
+        private GroupConfig getConfigFor(String groupTag) {
+            return mConfig.getConfigFor(groupTag);
+        }
+    }
+
+    public static class IncrementalState {
+        public final Map<String, Integer> argumentInterningMap = new HashMap<>();
+        public final Map<String, Integer> stacktraceInterningMap = new HashMap<>();
+        public boolean clearReported = false;
+    }
+
+    private static class ProtoLogConfig {
+        private final LogLevel mDefaultLogFromLevel;
+        private final Map<String, GroupConfig> mGroupConfigs;
+
+        private static final ProtoLogConfig DEFAULT =
+                new ProtoLogConfig(LogLevel.WTF, new HashMap<>());
+
+        private ProtoLogConfig(
+                LogLevel defaultLogFromLevel, Map<String, GroupConfig> groupConfigs) {
+            this.mDefaultLogFromLevel = defaultLogFromLevel;
+            this.mGroupConfigs = groupConfigs;
+        }
+
+        private GroupConfig getConfigFor(String groupTag) {
+            return mGroupConfigs.getOrDefault(groupTag, getDefaultGroupConfig());
+        }
+
+        private GroupConfig getDefaultGroupConfig() {
+            return new GroupConfig(mDefaultLogFromLevel, false);
+        }
+    }
+
+    public static class GroupConfig {
+        public final LogLevel logFrom;
+        public final boolean collectStackTrace;
+
+        public GroupConfig(LogLevel logFromLevel, boolean collectStackTrace) {
+            this.logFrom = logFromLevel;
+            this.collectStackTrace = collectStackTrace;
+        }
+    }
+
+    private ProtoLogConfig readProtoLogConfig(ProtoInputStream configStream)
+            throws IOException {
+        final long config_token = configStream.start(PROTOLOG_CONFIG);
+
+        LogLevel defaultLogFromLevel = LogLevel.WTF;
+        final Map<String, GroupConfig> groupConfigs = new HashMap<>();
+
+        while (configStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            if (configStream.getFieldNumber() == (int) TRACING_MODE) {
+                int tracingMode = configStream.readInt(TRACING_MODE);
+                switch (tracingMode) {
+                    case PerfettoTrace.ProtoLogConfig.DEFAULT:
+                        break;
+                    case PerfettoTrace.ProtoLogConfig.ENABLE_ALL:
+                        defaultLogFromLevel = LogLevel.DEBUG;
+                        break;
+                    default:
+                        throw new RuntimeException("Unhandled ProtoLog tracing mode type");
+                }
+            }
+            if (configStream.getFieldNumber() == (int) GROUP_OVERRIDES) {
+                final long group_overrides_token  = configStream.start(GROUP_OVERRIDES);
+
+                String tag = null;
+                LogLevel logFromLevel = defaultLogFromLevel;
+                boolean collectStackTrace = false;
+                while (configStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                    if (configStream.getFieldNumber() == (int) GROUP_NAME) {
+                        tag = configStream.readString(GROUP_NAME);
+                    }
+                    if (configStream.getFieldNumber() == (int) LOG_FROM) {
+                        final int logFromInt = configStream.readInt(LOG_FROM);
+                        switch (logFromInt) {
+                            case (PerfettoTrace.PROTOLOG_LEVEL_DEBUG): {
+                                logFromLevel = LogLevel.DEBUG;
+                                break;
+                            }
+                            case (PerfettoTrace.PROTOLOG_LEVEL_VERBOSE): {
+                                logFromLevel = LogLevel.VERBOSE;
+                                break;
+                            }
+                            case (PerfettoTrace.PROTOLOG_LEVEL_INFO): {
+                                logFromLevel = LogLevel.INFO;
+                                break;
+                            }
+                            case (PerfettoTrace.PROTOLOG_LEVEL_WARN): {
+                                logFromLevel = LogLevel.WARN;
+                                break;
+                            }
+                            case (PerfettoTrace.PROTOLOG_LEVEL_ERROR): {
+                                logFromLevel = LogLevel.ERROR;
+                                break;
+                            }
+                            case (PerfettoTrace.PROTOLOG_LEVEL_WTF): {
+                                logFromLevel = LogLevel.WTF;
+                                break;
+                            }
+                            default: {
+                                throw new RuntimeException("Unhandled log level");
+                            }
+                        }
+                    }
+                    if (configStream.getFieldNumber() == (int) COLLECT_STACKTRACE) {
+                        collectStackTrace = configStream.readBoolean(COLLECT_STACKTRACE);
+                    }
+                }
+
+                if (tag == null) {
+                    throw new RuntimeException("Failed to decode proto config. "
+                            + "Got a group override without a group tag.");
+                }
+
+                groupConfigs.put(tag, new GroupConfig(logFromLevel, collectStackTrace));
+
+                configStream.end(group_overrides_token);
+            }
+        }
+
+        configStream.end(config_token);
+
+        return new ProtoLogConfig(defaultLogFromLevel, groupConfigs);
+    }
+
+    public static class Instance extends DataSourceInstance {
+
+        private final Runnable mOnStart;
+        private final Runnable mOnFlush;
+        private final Runnable mOnStop;
+        private final ProtoLogConfig mConfig;
+
+        public Instance(
+                DataSource<Instance, TlsState, IncrementalState> dataSource,
+                int instanceIdx,
+                ProtoLogConfig config,
+                Runnable onStart,
+                Runnable onFlush,
+                Runnable onStop
+        ) {
+            super(dataSource, instanceIdx);
+            this.mOnStart = onStart;
+            this.mOnFlush = onFlush;
+            this.mOnStop = onStop;
+            this.mConfig = config;
+        }
+
+        @Override
+        public void onStart(StartCallbackArguments args) {
+            this.mOnStart.run();
+        }
+
+        @Override
+        public void onFlush(FlushCallbackArguments args) {
+            this.mOnFlush.run();
+        }
+
+        @Override
+        public void onStop(StopCallbackArguments args) {
+            this.mOnStop.run();
+        }
+    }
+}
diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java
index 527cfdd..8965385 100644
--- a/core/java/com/android/internal/protolog/ProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java
@@ -16,30 +16,35 @@
 
 package com.android.internal.protolog;
 
+import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LEGACY_OUTPUT_FILE_PATH;
+import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LEGACY_VIEWER_CONFIG_PATH;
+import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.VIEWER_CONFIG_PATH;
+
 import android.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.IProtoLog;
 import com.android.internal.protolog.common.IProtoLogGroup;
-
-import java.io.File;
+import com.android.internal.protolog.common.LogLevel;
+import com.android.internal.protolog.common.ProtoLogToolInjected;
 
 /**
  * A service for the ProtoLog logging system.
  */
-public class ProtoLogImpl extends BaseProtoLogImpl {
-    private static final int BUFFER_CAPACITY = 1024 * 1024;
-    private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.winscope";
-    private static final String VIEWER_CONFIG_FILENAME = "/system/etc/protolog.conf.json.gz";
-    private static final int PER_CHUNK_SIZE = 1024;
+public class ProtoLogImpl {
+    private static IProtoLog sServiceInstance = null;
 
-    private static ProtoLogImpl sServiceInstance = null;
+    @ProtoLogToolInjected(VIEWER_CONFIG_PATH)
+    private static String sViewerConfigPath;
 
-    static {
-        addLogGroupEnum(ProtoLogGroup.values());
-    }
+    @ProtoLogToolInjected(LEGACY_VIEWER_CONFIG_PATH)
+    private static String sLegacyViewerConfigPath;
+
+    @ProtoLogToolInjected(LEGACY_OUTPUT_FILE_PATH)
+    private static String sLegacyOutputFilePath;
 
     /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void d(IProtoLogGroup group, int messageHash, int paramsMask,
+    public static void d(IProtoLogGroup group, long messageHash, int paramsMask,
             @Nullable String messageString,
             Object... args) {
         getSingleInstance()
@@ -47,7 +52,7 @@
     }
 
     /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void v(IProtoLogGroup group, int messageHash, int paramsMask,
+    public static void v(IProtoLogGroup group, long messageHash, int paramsMask,
             @Nullable String messageString,
             Object... args) {
         getSingleInstance().log(LogLevel.VERBOSE, group, messageHash, paramsMask, messageString,
@@ -55,21 +60,21 @@
     }
 
     /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void i(IProtoLogGroup group, int messageHash, int paramsMask,
+    public static void i(IProtoLogGroup group, long messageHash, int paramsMask,
             @Nullable String messageString,
             Object... args) {
         getSingleInstance().log(LogLevel.INFO, group, messageHash, paramsMask, messageString, args);
     }
 
     /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void w(IProtoLogGroup group, int messageHash, int paramsMask,
+    public static void w(IProtoLogGroup group, long messageHash, int paramsMask,
             @Nullable String messageString,
             Object... args) {
         getSingleInstance().log(LogLevel.WARN, group, messageHash, paramsMask, messageString, args);
     }
 
     /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void e(IProtoLogGroup group, int messageHash, int paramsMask,
+    public static void e(IProtoLogGroup group, long messageHash, int paramsMask,
             @Nullable String messageString,
             Object... args) {
         getSingleInstance()
@@ -77,40 +82,36 @@
     }
 
     /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void wtf(IProtoLogGroup group, int messageHash, int paramsMask,
+    public static void wtf(IProtoLogGroup group, long messageHash, int paramsMask,
             @Nullable String messageString,
             Object... args) {
         getSingleInstance().log(LogLevel.WTF, group, messageHash, paramsMask, messageString, args);
     }
 
-    /** Returns true iff logging is enabled for the given {@code IProtoLogGroup}. */
     public static boolean isEnabled(IProtoLogGroup group) {
-        return group.isLogToLogcat()
-                || (group.isLogToProto() && getSingleInstance().isProtoEnabled());
+        // TODO: Implement for performance reasons, with optional level parameter?
+        return true;
     }
 
     /**
      * Returns the single instance of the ProtoLogImpl singleton class.
      */
-    public static synchronized ProtoLogImpl getSingleInstance() {
+    public static synchronized IProtoLog getSingleInstance() {
         if (sServiceInstance == null) {
-            sServiceInstance = new ProtoLogImpl(
-                    new File(LOG_FILENAME)
-                    , BUFFER_CAPACITY
-                    , new ProtoLogViewerConfigReader()
-                    , PER_CHUNK_SIZE);
+            if (android.tracing.Flags.perfettoProtologTracing()) {
+                sServiceInstance =
+                        new PerfettoProtoLogImpl(sViewerConfigPath);
+            } else {
+                sServiceInstance =
+                        new LegacyProtoLogImpl(sLegacyOutputFilePath, sLegacyViewerConfigPath);
+            }
         }
         return sServiceInstance;
     }
 
     @VisibleForTesting
-    public static synchronized void setSingleInstance(@Nullable ProtoLogImpl instance) {
+    public static synchronized void setSingleInstance(@Nullable IProtoLog instance) {
         sServiceInstance = instance;
     }
-
-    public ProtoLogImpl(File logFile, int bufferCapacity,
-            ProtoLogViewerConfigReader viewConfigReader, int perChunkSize) {
-        super(logFile, VIEWER_CONFIG_FILENAME, bufferCapacity, viewConfigReader, perChunkSize);
-  }
 }
 
diff --git a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
index aa30a77..3c206ac 100644
--- a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
+++ b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
@@ -1,48 +1,30 @@
-/*
- * 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.internal.protolog;
 
-import android.annotation.Nullable;
-import android.util.Slog;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MESSAGES;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData.MESSAGE;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData.MESSAGE_ID;
 
-import org.json.JSONException;
-import org.json.JSONObject;
+import android.util.proto.ProtoInputStream;
 
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
+import com.android.internal.protolog.common.ILogger;
+
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.util.Iterator;
 import java.util.Map;
-import java.util.TreeMap;
-import java.util.zip.GZIPInputStream;
 
-/**
- * Handles loading and parsing of ProtoLog viewer configuration.
- */
 public class ProtoLogViewerConfigReader {
-    private static final String TAG = "ProtoLogViewerConfigReader";
-    private Map<Integer, String> mLogMessageMap = null;
+    private final ViewerConfigInputStreamProvider mViewerConfigInputStreamProvider;
+    private Map<Long, String> mLogMessageMap = null;
 
-    /** Returns message format string for its hash or null if unavailable. */
-    public synchronized String getViewerString(int messageHash) {
+    public ProtoLogViewerConfigReader(
+            ViewerConfigInputStreamProvider viewerConfigInputStreamProvider) {
+        this.mViewerConfigInputStreamProvider = viewerConfigInputStreamProvider;
+    }
+
+    /**
+     * Returns message format string for its hash or null if unavailable
+     * or the viewer config is not loaded into memory.
+     */
+    public synchronized String getViewerString(long messageHash) {
         if (mLogMessageMap != null) {
             return mLogMessageMap.get(messageHash);
         } else {
@@ -51,75 +33,61 @@
     }
 
     /**
-     * Reads the specified viewer configuration file. Does nothing if the config is already loaded.
+     * Loads the viewer config into memory. No-op if already loaded in memory.
      */
-    public synchronized void loadViewerConfig(PrintWriter pw, String viewerConfigFilename) {
-        try {
-            loadViewerConfig(new GZIPInputStream(new FileInputStream(viewerConfigFilename)));
-            logAndPrintln(pw, "Loaded " + mLogMessageMap.size()
-                    + " log definitions from " + viewerConfigFilename);
-        } catch (FileNotFoundException e) {
-            logAndPrintln(pw, "Unable to load log definitions: File "
-                    + viewerConfigFilename + " not found." + e);
-        } catch (IOException e) {
-            logAndPrintln(pw, "Unable to load log definitions: IOException while reading "
-                    + viewerConfigFilename + ". " + e);
-        } catch (JSONException e) {
-            logAndPrintln(pw, "Unable to load log definitions: JSON parsing exception while reading "
-                    + viewerConfigFilename + ". " + e);
-        }
-    }
-
-    /**
-     * Reads the specified viewer configuration input stream.
-     * Does nothing if the config is already loaded.
-     */
-    public synchronized void loadViewerConfig(InputStream viewerConfigInputStream)
-            throws IOException, JSONException {
+    public synchronized void loadViewerConfig(ILogger logger) {
         if (mLogMessageMap != null) {
             return;
         }
-        InputStreamReader config = new InputStreamReader(viewerConfigInputStream);
-        BufferedReader reader = new BufferedReader(config);
-        StringBuilder builder = new StringBuilder();
-        String line;
-        while ((line = reader.readLine()) != null) {
-            builder.append(line).append('\n');
-        }
-        reader.close();
-        JSONObject json = new JSONObject(builder.toString());
-        JSONObject messages = json.getJSONObject("messages");
 
-        mLogMessageMap = new TreeMap<>();
-        Iterator it = messages.keys();
-        while (it.hasNext()) {
-            String key = (String) it.next();
-            try {
-                int hash = Integer.parseInt(key);
-                JSONObject val = messages.getJSONObject(key);
-                String msg = val.getString("message");
-                mLogMessageMap.put(hash, msg);
-            } catch (NumberFormatException expected) {
-                // Not a messageHash - skip it
-            }
+        try {
+            doLoadViewerConfig();
+            logger.log("Loaded " + mLogMessageMap.size() + " log definitions");
+        } catch (IOException e) {
+            logger.log("Unable to load log definitions: "
+                    + "IOException while processing viewer config" + e);
         }
     }
 
     /**
-     * Returns the number of loaded log definitions kept in memory.
+     * Unload the viewer config from memory.
      */
-    public synchronized int knownViewerStringsNumber() {
-        if (mLogMessageMap != null) {
-            return mLogMessageMap.size();
-        }
-        return 0;
+    public synchronized void unloadViewerConfig() {
+        mLogMessageMap = null;
     }
 
-    static void logAndPrintln(@Nullable PrintWriter pw, String msg) {
-        Slog.i(TAG, msg);
-        if (pw != null) {
-            pw.println(msg);
-            pw.flush();
+    private void doLoadViewerConfig() throws IOException {
+        final ProtoInputStream pis = mViewerConfigInputStreamProvider.getInputStream();
+
+        while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            if (pis.getFieldNumber() == (int) MESSAGES) {
+                final long inMessageToken = pis.start(MESSAGES);
+
+                long messageId = 0;
+                String message = null;
+                while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                    switch (pis.getFieldNumber()) {
+                        case (int) MESSAGE_ID:
+                            messageId = pis.readLong(MESSAGE_ID);
+                            break;
+                        case (int) MESSAGE:
+                            message = pis.readString(MESSAGE);
+                            break;
+                    }
+                }
+
+                if (messageId == 0) {
+                    throw new IOException("Failed to get message id");
+                }
+
+                if (message == null) {
+                    throw new IOException("Failed to get message string");
+                }
+
+                mLogMessageMap.put(messageId, message);
+
+                pis.end(inMessageToken);
+            }
         }
     }
 }
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt b/core/java/com/android/internal/protolog/ViewerConfigInputStreamProvider.java
similarity index 72%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
copy to core/java/com/android/internal/protolog/ViewerConfigInputStreamProvider.java
index 8ad0a08..334f548 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
+++ b/core/java/com/android/internal/protolog/ViewerConfigInputStreamProvider.java
@@ -14,8 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.systemui.volume.panel.component.mediaoutput
+package com.android.internal.protolog;
 
-import dagger.Module
+import android.util.proto.ProtoInputStream;
 
-@Module interface MediaOutputModule
+public interface ViewerConfigInputStreamProvider {
+    /**
+     * @return a ProtoInputStream.
+     */
+    ProtoInputStream getInputStream();
+}
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt b/core/java/com/android/internal/protolog/common/ILogger.java
similarity index 76%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
copy to core/java/com/android/internal/protolog/common/ILogger.java
index 8ad0a08..cc6fa5e 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
+++ b/core/java/com/android/internal/protolog/common/ILogger.java
@@ -14,8 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.systemui.volume.panel.component.mediaoutput
+package com.android.internal.protolog.common;
 
-import dagger.Module
-
-@Module interface MediaOutputModule
+public interface ILogger {
+    /**
+     * Log a message.
+     * @param message The log message.
+     */
+    void log(String message);
+}
diff --git a/core/java/com/android/internal/protolog/common/IProtoLog.java b/core/java/com/android/internal/protolog/common/IProtoLog.java
new file mode 100644
index 0000000..c06d14b
--- /dev/null
+++ b/core/java/com/android/internal/protolog/common/IProtoLog.java
@@ -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.internal.protolog.common;
+
+/**
+ * Interface for ProtoLog implementations.
+ */
+public interface IProtoLog {
+
+    /**
+     * Log a ProtoLog message
+     * @param logLevel Log level of the proto message.
+     * @param group The group this message belongs to.
+     * @param messageHash The hash of the message.
+     * @param paramsMask The parameters mask of the message.
+     * @param messageString The message string.
+     * @param args The arguments of the message.
+     */
+    void log(LogLevel logLevel, IProtoLogGroup group, long messageHash, int paramsMask,
+             String messageString, Object[] args);
+
+    /**
+     * Check if ProtoLog is tracing.
+     * @return true iff a ProtoLog tracing session is active.
+     */
+    boolean isProtoEnabled();
+
+    /**
+     * Start logging log groups to logcat
+     * @param groups Groups to start text logging for
+     * @return status code
+     */
+    int startLoggingToLogcat(String[] groups, ILogger logger);
+
+    /**
+     * Stop logging log groups to logcat
+     * @param groups Groups to start text logging for
+     * @return status code
+     */
+    int stopLoggingToLogcat(String[] groups, ILogger logger);
+}
diff --git a/core/java/com/android/internal/protolog/common/IProtoLogGroup.java b/core/java/com/android/internal/protolog/common/IProtoLogGroup.java
index e3db468..4e9686f99 100644
--- a/core/java/com/android/internal/protolog/common/IProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/common/IProtoLogGroup.java
@@ -26,6 +26,7 @@
     boolean isEnabled();
 
     /**
+     * @deprecated TODO(b/324128613) remove once we migrate fully to Perfetto
      * is binary logging enabled for the group.
      */
     boolean isLogToProto();
diff --git a/core/java/com/android/internal/protolog/common/ProtoLog.java b/core/java/com/android/internal/protolog/common/ProtoLog.java
index 8870096..18e3f66 100644
--- a/core/java/com/android/internal/protolog/common/ProtoLog.java
+++ b/core/java/com/android/internal/protolog/common/ProtoLog.java
@@ -16,8 +16,6 @@
 
 package com.android.internal.protolog.common;
 
-import android.util.Log;
-
 /**
  * ProtoLog API - exposes static logging methods. Usage of this API is similar
  * to {@code android.utils.Log} class. Instead of plain text log messages each call consists of
@@ -55,9 +53,6 @@
             throw new UnsupportedOperationException(
                     "ProtoLog calls MUST be processed with ProtoLogTool");
         }
-        if (group.isLogToLogcat()) {
-            Log.d(group.getTag(), String.format(messageString, args));
-        }
     }
 
     /**
@@ -73,9 +68,6 @@
             throw new UnsupportedOperationException(
                     "ProtoLog calls MUST be processed with ProtoLogTool");
         }
-        if (group.isLogToLogcat()) {
-            Log.v(group.getTag(), String.format(messageString, args));
-        }
     }
 
     /**
@@ -91,9 +83,6 @@
             throw new UnsupportedOperationException(
                     "ProtoLog calls MUST be processed with ProtoLogTool");
         }
-        if (group.isLogToLogcat()) {
-            Log.i(group.getTag(), String.format(messageString, args));
-        }
     }
 
     /**
@@ -109,9 +98,6 @@
             throw new UnsupportedOperationException(
                     "ProtoLog calls MUST be processed with ProtoLogTool");
         }
-        if (group.isLogToLogcat()) {
-            Log.w(group.getTag(), String.format(messageString, args));
-        }
     }
 
     /**
@@ -127,9 +113,6 @@
             throw new UnsupportedOperationException(
                     "ProtoLog calls MUST be processed with ProtoLogTool");
         }
-        if (group.isLogToLogcat()) {
-            Log.e(group.getTag(), String.format(messageString, args));
-        }
     }
 
     /**
@@ -145,8 +128,30 @@
             throw new UnsupportedOperationException(
                     "ProtoLog calls MUST be processed with ProtoLogTool");
         }
-        if (group.isLogToLogcat()) {
-            Log.wtf(group.getTag(), String.format(messageString, args));
+    }
+
+    /**
+     * Check if ProtoLog isEnabled for a target group.
+     * @param group Group to check enable status of.
+     * @return true iff this is being logged.
+     */
+    public static boolean isEnabled(IProtoLogGroup group) {
+        if (REQUIRE_PROTOLOGTOOL) {
+            throw new UnsupportedOperationException(
+                    "ProtoLog calls MUST be processed with ProtoLogTool");
         }
+        return false;
+    }
+
+    /**
+     * Get the single ProtoLog instance.
+     * @return A singleton instance of ProtoLog.
+     */
+    public static IProtoLog getSingleInstance() {
+        if (REQUIRE_PROTOLOGTOOL) {
+            throw new UnsupportedOperationException(
+                    "ProtoLog calls MUST be processed with ProtoLogTool");
+        }
+        return null;
     }
 }
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt b/core/java/com/android/internal/protolog/common/ProtoLogToolInjected.java
similarity index 64%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
copy to core/java/com/android/internal/protolog/common/ProtoLogToolInjected.java
index 8ad0a08..ffd0d76 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
+++ b/core/java/com/android/internal/protolog/common/ProtoLogToolInjected.java
@@ -14,8 +14,15 @@
  * limitations under the License.
  */
 
-package com.android.systemui.volume.panel.component.mediaoutput
 
-import dagger.Module
+package com.android.internal.protolog.common;
 
-@Module interface MediaOutputModule
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target({ElementType.FIELD, ElementType.PARAMETER})
+public @interface ProtoLogToolInjected {
+    enum Value { VIEWER_CONFIG_PATH, LEGACY_OUTPUT_FILE_PATH, LEGACY_VIEWER_CONFIG_PATH }
+
+    Value value();
+}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index d463b62..6ffc638 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -360,8 +360,12 @@
     /** Shows rear display educational dialog */
     void showRearDisplayDialog(int currentBaseState);
 
-    /** Called when requested to go to fullscreen from the active split app. */
-    void goToFullscreenFromSplit();
+    /**
+     *  Called when requested to go to fullscreen from the focused app.
+     *
+     *  @param displayId the id of the current display.
+     */
+    void moveFocusedTaskToFullscreen(int displayId);
 
     /**
      * Enters stage split from a current running app.
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 1f4503a..dc3b5a8 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -65,12 +65,21 @@
     InputMethodSubtype getLastInputMethodSubtype(int userId);
 
     boolean showSoftInput(in IInputMethodClient client, @nullable IBinder windowToken,
-            in @nullable ImeTracker.Token statsToken, int flags, int lastClickToolType,
+            in ImeTracker.Token statsToken, int flags, int lastClickToolType,
             in @nullable ResultReceiver resultReceiver, int reason);
     boolean hideSoftInput(in IInputMethodClient client, @nullable IBinder windowToken,
-            in @nullable ImeTracker.Token statsToken, int flags,
+            in ImeTracker.Token statsToken, int flags,
             in @nullable ResultReceiver resultReceiver, int reason);
 
+    /**
+     * A test API for CTS to request hiding the current soft input window, with the request origin
+     * on the server side.
+     */
+    @EnforcePermission("TEST_INPUT_METHOD")
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+            + "android.Manifest.permission.TEST_INPUT_METHOD)")
+    void hideSoftInputFromServerForTest();
+
     // TODO(b/293640003): Remove method once Flags.useZeroJankProxy() is enabled.
     // If windowToken is null, this just does startInput().  Otherwise this reports that a window
     // has gained focus, and if 'editorInfo' is non-null then also does startInput.
diff --git a/core/java/com/android/internal/widget/ConversationAvatarData.java b/core/java/com/android/internal/widget/ConversationAvatarData.java
new file mode 100644
index 0000000..e04772f
--- /dev/null
+++ b/core/java/com/android/internal/widget/ConversationAvatarData.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.graphics.drawable.Drawable;
+
+/**
+ * @hide
+ */
+interface ConversationAvatarData {
+    final class OneToOneConversationAvatarData implements ConversationAvatarData {
+        final Drawable mDrawable;
+
+        OneToOneConversationAvatarData(Drawable drawable) {
+            mDrawable = drawable;
+        }
+    }
+
+    final class GroupConversationAvatarData implements ConversationAvatarData {
+        final Drawable mLastIcon;
+        final Drawable mSecondLastIcon;
+
+        GroupConversationAvatarData(Drawable lastIcon, Drawable secondLastIcon) {
+            mLastIcon = lastIcon;
+            mSecondLastIcon = secondLastIcon;
+        }
+    }
+}
diff --git a/core/java/com/android/internal/widget/ConversationHeaderData.java b/core/java/com/android/internal/widget/ConversationHeaderData.java
new file mode 100644
index 0000000..0953b39
--- /dev/null
+++ b/core/java/com/android/internal/widget/ConversationHeaderData.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.annotation.Nullable;
+
+/**
+ * @hide
+ */
+final class ConversationHeaderData {
+    private final CharSequence mConversationText;
+
+    private final ConversationAvatarData mConversationAvatarData;
+
+    ConversationHeaderData(CharSequence conversationText,
+            ConversationAvatarData conversationAvatarData) {
+        mConversationText = conversationText;
+        mConversationAvatarData = conversationAvatarData;
+    }
+
+    @Nullable
+    CharSequence getConversationText() {
+        return mConversationText;
+    }
+
+    @Nullable
+    ConversationAvatarData getConversationAvatar() {
+        return mConversationAvatarData;
+    }
+}
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 889434f..06835f0 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -34,8 +34,10 @@
 import android.content.res.ColorStateList;
 import android.graphics.Rect;
 import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.Icon;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.text.Spannable;
@@ -59,8 +61,11 @@
 import android.widget.LinearLayout;
 import android.widget.RemoteViews;
 import android.widget.TextView;
+import android.widget.flags.Flags;
 
 import com.android.internal.R;
+import com.android.internal.widget.ConversationAvatarData.GroupConversationAvatarData;
+import com.android.internal.widget.ConversationAvatarData.OneToOneConversationAvatarData;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -403,11 +408,14 @@
      */
     @RemotableViewMethod(asyncImpl = "setDataAsync")
     public void setData(Bundle extras) {
-        bind(parseMessagingData(extras, /* usePrecomputedText= */ false));
+        bind(parseMessagingData(extras,
+                /* usePrecomputedText= */ false,
+                /*includeConversationIcon= */false));
     }
 
     @NonNull
-    private MessagingData parseMessagingData(Bundle extras, boolean usePrecomputedText) {
+    private MessagingData parseMessagingData(Bundle extras, boolean usePrecomputedText,
+            boolean includeConversationIcon) {
         Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
         List<Notification.MessagingStyle.Message> newMessages =
                 Notification.MessagingStyle.Message.getMessagesFromBundleArray(messages);
@@ -438,8 +446,20 @@
         // Lets first find the groups (populate `groups` and `senders`)
         findGroups(newHistoricMessagingMessages, newMessagingMessages, user, groups, senders);
 
+        // load conversation header data, avatar and title.
+        final ConversationHeaderData conversationHeaderData;
+        if (includeConversationIcon && Flags.conversationStyleSetAvatarAsync()) {
+            conversationHeaderData = loadConversationHeaderData(mIsOneToOne,
+                    mConversationTitle,
+                    mShortcutIcon,
+                    mLargeIcon, newMessagingMessages, user, groups, mLayoutColor);
+        } else {
+            conversationHeaderData = null;
+        }
+
         return new MessagingData(user, showSpinner, unreadCount,
-                newHistoricMessagingMessages, newMessagingMessages, groups, senders);
+                newHistoricMessagingMessages, newMessagingMessages, groups, senders,
+                conversationHeaderData);
     }
 
     /**
@@ -457,7 +477,9 @@
         }
 
         final MessagingData messagingData =
-                parseMessagingData(extras, /* usePrecomputedText= */ true);
+                parseMessagingData(extras,
+                        /* usePrecomputedText= */ true,
+                        /*includeConversationIcon=*/true);
 
         return () -> {
             finalizeInflate(messagingData.getHistoricMessagingMessages());
@@ -536,11 +558,10 @@
 
         mMessages = messagingData.getNewMessagingMessages();
         mHistoricMessages = messagingData.getHistoricMessagingMessages();
-
         updateHistoricMessageVisibility();
         updateTitleAndNamesDisplay();
 
-        updateConversationLayout();
+        updateConversationLayout(messagingData);
 
         // Recycle everything at the end of the update, now that we know it's no longer needed.
         for (MessagingLinearLayout.MessagingChild child : mToRecycle) {
@@ -552,7 +573,31 @@
     /**
      * Update the layout according to the data provided (i.e mIsOneToOne, expanded etc);
      */
-    private void updateConversationLayout() {
+    private void updateConversationLayout(MessagingData messagingData) {
+        if (!Flags.conversationStyleSetAvatarAsync()) {
+            computeAndSetConversationAvatarAndName();
+        } else {
+            ConversationHeaderData conversationHeaderData =
+                    messagingData.getConversationHeaderData();
+            if (conversationHeaderData == null) {
+                conversationHeaderData = loadConversationHeaderData(mIsOneToOne,
+                        mConversationTitle, mShortcutIcon, mLargeIcon, mMessages, mUser,
+                        messagingData.getGroups(),
+                        mLayoutColor);
+            }
+            setConversationAvatarAndNameFromData(conversationHeaderData);
+        }
+
+        updateAppName();
+        updateIconPositionAndSize();
+        updateImageMessages();
+        updatePaddingsBasedOnContentAvailability();
+        updateActionListPadding();
+        updateAppNameDividerVisibility();
+    }
+
+    @Deprecated
+    private void computeAndSetConversationAvatarAndName() {
         // Set avatar and name
         CharSequence conversationText = mConversationTitle;
         mConversationIcon = mShortcutIcon;
@@ -603,12 +648,43 @@
         // Update if the groups can hide the sender if they are first (applies to 1:1 conversations)
         // This needs to happen after all of the above o update all of the groups
         mPeopleHelper.maybeHideFirstSenderName(mGroups, mIsOneToOne, conversationText);
-        updateAppName();
-        updateIconPositionAndSize();
-        updateImageMessages();
-        updatePaddingsBasedOnContentAvailability();
-        updateActionListPadding();
-        updateAppNameDividerVisibility();
+    }
+
+    private void setConversationAvatarAndNameFromData(
+            ConversationHeaderData conversationHeaderData) {
+        final OneToOneConversationAvatarData oneToOneConversationDrawable;
+        final GroupConversationAvatarData groupConversationAvatarData;
+        final ConversationAvatarData conversationAvatar =
+                conversationHeaderData.getConversationAvatar();
+        if (conversationAvatar instanceof OneToOneConversationAvatarData) {
+            oneToOneConversationDrawable =
+                    ((OneToOneConversationAvatarData) conversationAvatar);
+            groupConversationAvatarData = null;
+        } else {
+            oneToOneConversationDrawable = null;
+            groupConversationAvatarData = ((GroupConversationAvatarData) conversationAvatar);
+        }
+
+        if (oneToOneConversationDrawable != null) {
+            mConversationIconView.setVisibility(VISIBLE);
+            mConversationFacePile.setVisibility(GONE);
+            mConversationIconView.setImageDrawable(oneToOneConversationDrawable.mDrawable);
+        } else {
+            mConversationIconView.setVisibility(GONE);
+            // This will also inflate it!
+            mConversationFacePile.setVisibility(VISIBLE);
+            // rebind the value to the inflated view instead of the stub
+            mConversationFacePile = findViewById(R.id.conversation_face_pile);
+            bindFacePile(groupConversationAvatarData);
+        }
+        CharSequence conversationText = conversationHeaderData.getConversationText();
+        if (TextUtils.isEmpty(conversationText)) {
+            conversationText = mIsOneToOne ? mFallbackChatName : mFallbackGroupChatName;
+        }
+        mConversationText.setText(conversationText);
+        // Update if the groups can hide the sender if they are first (applies to 1:1 conversations)
+        // This needs to happen after all of the above o update all of the groups
+        mPeopleHelper.maybeHideFirstSenderName(mGroups, mIsOneToOne, conversationText);
     }
 
     private void updateActionListPadding() {
@@ -675,7 +751,12 @@
         topView.setImageIcon(secondLastIcon);
     }
 
+    @Deprecated
     private void bindFacePile() {
+        bindFacePile(null);
+    }
+
+    private void bindFacePile(@Nullable GroupConversationAvatarData groupConversationAvatarData) {
         ImageView bottomBackground = mConversationFacePile.findViewById(
                 R.id.conversation_face_pile_bottom_background);
         ImageView bottomView = mConversationFacePile.findViewById(
@@ -683,7 +764,13 @@
         ImageView topView = mConversationFacePile.findViewById(
                 R.id.conversation_face_pile_top);
 
-        bindFacePile(bottomBackground, bottomView, topView);
+        if (groupConversationAvatarData == null) {
+            bindFacePile(bottomBackground, bottomView, topView);
+        } else {
+            bindFacePileWithDrawable(bottomBackground, bottomView, topView,
+                    groupConversationAvatarData);
+
+        }
 
         int conversationAvatarSize;
         int facepileAvatarSize;
@@ -718,6 +805,13 @@
         bottomBackground.setLayoutParams(layoutParams);
     }
 
+    private void bindFacePileWithDrawable(ImageView bottomBackground, ImageView bottomView,
+            ImageView topView, GroupConversationAvatarData groupConversationAvatarData) {
+        applyNotificationBackgroundColor(bottomBackground);
+        bottomView.setImageDrawable(groupConversationAvatarData.mLastIcon);
+        topView.setImageDrawable(groupConversationAvatarData.mSecondLastIcon);
+    }
+
     private void updateAppName() {
         mAppName.setVisibility(mIsCollapsed ? GONE : VISIBLE);
     }
@@ -789,22 +883,62 @@
                 mMessagingLinearLayout.getPaddingBottom());
     }
 
+    /**
+     * async version of {@link ConversationLayout#setLargeIcon}
+     */
     @RemotableViewMethod
+    public Runnable setLargeIconAsync(Icon largeIcon) {
+        if (!Flags.conversationStyleSetAvatarAsync()) {
+            return () -> setLargeIcon(largeIcon);
+        }
+
+        mLargeIcon = largeIcon;
+        return NotificationRunnables.NOOP;
+    }
+
+    @RemotableViewMethod(asyncImpl = "setLargeIconAsync")
     public void setLargeIcon(Icon largeIcon) {
         mLargeIcon = largeIcon;
     }
 
+    /**
+     * async version of {@link ConversationLayout#setShortcutIcon}
+     */
     @RemotableViewMethod
+    public Runnable setShortcutIconAsync(Icon shortcutIcon) {
+        if (!Flags.conversationStyleSetAvatarAsync()) {
+            return () -> setShortcutIcon(shortcutIcon);
+        }
+
+        mShortcutIcon = shortcutIcon;
+        return NotificationRunnables.NOOP;
+    }
+
+    @RemotableViewMethod(asyncImpl = "setShortcutIconAsync")
     public void setShortcutIcon(Icon shortcutIcon) {
         mShortcutIcon = shortcutIcon;
     }
 
     /**
+     * async version of {@link ConversationLayout#setConversationTitle}
+     */
+    @RemotableViewMethod
+    public Runnable setConversationTitleAsync(CharSequence conversationTitle) {
+        if (!Flags.conversationStyleSetAvatarAsync()) {
+            return () -> setConversationTitle(conversationTitle);
+        }
+
+        // Remove formatting from the title.
+        mConversationTitle = conversationTitle != null ? conversationTitle.toString() : null;
+        return NotificationRunnables.NOOP;
+    }
+
+    /**
      * Sets the conversation title of this conversation.
      *
      * @param conversationTitle the conversation title
      */
-    @RemotableViewMethod
+    @RemotableViewMethod(asyncImpl = "setConversationTitleAsync")
     public void setConversationTitle(CharSequence conversationTitle) {
         // Remove formatting from the title.
         mConversationTitle = conversationTitle != null ? conversationTitle.toString() : null;
@@ -888,12 +1022,37 @@
         }
     }
 
+    /**
+     * async version of {@link ConversationLayout#setLayoutColor}
+     */
     @RemotableViewMethod
+    public Runnable setLayoutColorAsync(int color) {
+        if (!Flags.conversationStyleSetAvatarAsync()) {
+            return () -> setLayoutColor(color);
+        }
+
+        mLayoutColor = color;
+        return NotificationRunnables.NOOP;
+    }
+
+    @RemotableViewMethod(asyncImpl = "setLayoutColorAsync")
     public void setLayoutColor(int color) {
         mLayoutColor = color;
     }
 
+    /**
+     * async version of {@link ConversationLayout#setIsOneToOne}
+     */
     @RemotableViewMethod
+    public Runnable setIsOneToOneAsync(boolean oneToOne) {
+        if (!Flags.conversationStyleSetAvatarAsync()) {
+            return () -> setIsOneToOne(oneToOne);
+        }
+        mIsOneToOne = oneToOne;
+        return NotificationRunnables.NOOP;
+    }
+
+    @RemotableViewMethod(asyncImpl = "setIsOneToOneAsync")
     public void setIsOneToOne(boolean oneToOne) {
         mIsOneToOne = oneToOne;
     }
@@ -1022,6 +1181,125 @@
         return person == null ? null : person.getKey() == null ? person.getName() : person.getKey();
     }
 
+    private ConversationHeaderData loadConversationHeaderData(boolean isOneToOne,
+            CharSequence conversationTitle, Icon shortcutIcon, Icon largeIcon,
+            List<MessagingMessage> messages,
+            Person user,
+            List<List<MessagingMessage>> groups, int layoutColor) {
+        Icon conversationIcon = shortcutIcon;
+        CharSequence conversationText = conversationTitle;
+        final CharSequence userKey = getKey(user);
+        if (isOneToOne) {
+            for (int i = messages.size() - 1; i >= 0; i--) {
+                final Notification.MessagingStyle.Message message = messages.get(i).getMessage();
+                final Person sender = message.getSenderPerson();
+                final CharSequence senderKey = getKey(sender);
+                if ((sender != null && senderKey != userKey) || i == 0) {
+                    if (conversationText == null || conversationText.length() == 0) {
+                        conversationText = sender != null ? sender.getName() : "";
+                    }
+                    if (conversationIcon == null) {
+                        conversationIcon = sender != null ? sender.getIcon()
+                                : mPeopleHelper.createAvatarSymbol(conversationText, "",
+                                        layoutColor);
+                    }
+                    break;
+                }
+            }
+        }
+
+        if (conversationIcon == null) {
+            conversationIcon = largeIcon;
+        }
+
+        if (isOneToOne || conversationIcon != null) {
+            return new ConversationHeaderData(
+                    conversationText,
+                    new OneToOneConversationAvatarData(
+                            resolveAvatarImage(conversationIcon)));
+        }
+
+        final List<List<Notification.MessagingStyle.Message>> groupMessages = new ArrayList<>();
+        for (int i = 0; i < groups.size(); i++) {
+            final List<Notification.MessagingStyle.Message> groupMessage = new ArrayList<>();
+            for (int j = 0; j < groups.get(i).size(); j++) {
+                groupMessage.add(groups.get(i).get(j).getMessage());
+            }
+            groupMessages.add(groupMessage);
+        }
+
+        final PeopleHelper.NameToPrefixMap nameToPrefixMap =
+                mPeopleHelper.mapUniqueNamesToPrefixWithGroupList(groupMessages);
+
+        Icon lastIcon = null;
+        Icon secondLastIcon = null;
+
+        CharSequence lastKey = null;
+
+        for (int i = groups.size() - 1; i >= 0; i--) {
+            final Notification.MessagingStyle.Message message = groups.get(i).get(0).getMessage();
+            final Person sender =
+                    message.getSenderPerson() != null ? message.getSenderPerson() : user;
+            final CharSequence senderKey = getKey(sender);
+            final boolean notUser = senderKey != userKey;
+            final boolean notIncluded = senderKey != lastKey;
+
+            if ((notUser && notIncluded) || (i == 0 && lastKey == null)) {
+                if (lastIcon == null) {
+                    if (sender.getIcon() != null) {
+                        lastIcon = sender.getIcon();
+                    } else {
+                        final CharSequence senderName =
+                                sender.getName() != null ? sender.getName() : "";
+                        lastIcon = mPeopleHelper.createAvatarSymbol(
+                                senderName, nameToPrefixMap.getPrefix(senderName),
+                                layoutColor);
+                    }
+                    lastKey = senderKey;
+                } else {
+                    if (sender.getIcon() != null) {
+                        secondLastIcon = sender.getIcon();
+                    } else {
+                        final CharSequence senderName =
+                                sender.getName() != null ? sender.getName() : "";
+                        secondLastIcon = mPeopleHelper.createAvatarSymbol(
+                                senderName, nameToPrefixMap.getPrefix(senderName),
+                                layoutColor);
+                    }
+                    break;
+                }
+            }
+        }
+
+        if (lastIcon == null) {
+            lastIcon = mPeopleHelper.createAvatarSymbol(
+                    "", "", layoutColor);
+        }
+
+        if (secondLastIcon == null) {
+            secondLastIcon = mPeopleHelper.createAvatarSymbol(
+                    "", "", layoutColor);
+        }
+
+        return new ConversationHeaderData(
+                conversationText,
+                new GroupConversationAvatarData(resolveAvatarImage(lastIcon),
+                        resolveAvatarImage(secondLastIcon)));
+    }
+
+    /**
+     * {@link ImageResolver#loadImage(Uri)} accepts Uri to load images. However Conversation Avatars
+     * are received as Icon. So, we can't make use of ImageResolver.
+     */
+    @Nullable
+    private Drawable resolveAvatarImage(Icon conversationIcon) {
+        try {
+            return LocalImageResolver.resolveImage(conversationIcon, getContext());
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
     /**
      * Creates new messages, reusing existing ones if they are available.
      *
diff --git a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
index 918d9c0..1d0e972 100644
--- a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
+++ b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
@@ -39,6 +39,6 @@
     boolean hasStableIds();
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
     boolean isCreated();
-    RemoteViews.RemoteCollectionItems getRemoteCollectionItems();
+    RemoteViews.RemoteCollectionItems getRemoteCollectionItems(int capSize);
 }
 
diff --git a/core/java/com/android/internal/widget/MessagingData.java b/core/java/com/android/internal/widget/MessagingData.java
index 42de60e..fb1f28f 100644
--- a/core/java/com/android/internal/widget/MessagingData.java
+++ b/core/java/com/android/internal/widget/MessagingData.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.widget;
 
+import android.annotation.Nullable;
 import android.app.Person;
 
 import java.util.List;
@@ -32,6 +33,8 @@
     private final List<Person> mSenders;
     private final int mUnreadCount;
 
+    private ConversationHeaderData mConversationHeaderData;
+
     MessagingData(Person user, boolean showSpinner,
             List<MessagingMessage> historicMessagingMessages,
             List<MessagingMessage> newMessagingMessages, List<List<MessagingMessage>> groups,
@@ -39,7 +42,7 @@
         this(user, showSpinner, /* unreadCount= */0,
                 historicMessagingMessages, newMessagingMessages,
                 groups,
-                senders);
+                senders, null);
     }
 
     MessagingData(Person user, boolean showSpinner,
@@ -47,7 +50,8 @@
             List<MessagingMessage> historicMessagingMessages,
             List<MessagingMessage> newMessagingMessages,
             List<List<MessagingMessage>> groups,
-            List<Person> senders) {
+            List<Person> senders,
+            @Nullable ConversationHeaderData conversationHeaderData) {
         mUser = user;
         mShowSpinner = showSpinner;
         mUnreadCount = unreadCount;
@@ -55,6 +59,7 @@
         mNewMessagingMessages = newMessagingMessages;
         mGroups = groups;
         mSenders = senders;
+        mConversationHeaderData = conversationHeaderData;
     }
 
     public Person getUser() {
@@ -84,4 +89,9 @@
     public List<List<MessagingMessage>> getGroups() {
         return mGroups;
     }
+
+    @Nullable
+    public ConversationHeaderData getConversationHeaderData() {
+        return mConversationHeaderData;
+    }
 }
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt b/core/java/com/android/internal/widget/NotificationRunnables.java
similarity index 81%
rename from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
rename to core/java/com/android/internal/widget/NotificationRunnables.java
index 8ad0a08..cb7ae61 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
+++ b/core/java/com/android/internal/widget/NotificationRunnables.java
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.volume.panel.component.mediaoutput
+package com.android.internal.widget;
 
-import dagger.Module
-
-@Module interface MediaOutputModule
+public final class NotificationRunnables {
+    public static final Runnable NOOP = () -> {
+    };
+}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 240028c..76e7138 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -400,6 +400,7 @@
                 "libbinary_parse",
                 "libdng_sdk",
                 "libft2",
+                "libhostgraphics",
                 "libhwui",
                 "libimage_type_recognition",
                 "libjpeg",
diff --git a/core/jni/LayoutlibLoader.cpp b/core/jni/LayoutlibLoader.cpp
index 01e9f43..d5f17da 100644
--- a/core/jni/LayoutlibLoader.cpp
+++ b/core/jni/LayoutlibLoader.cpp
@@ -362,6 +362,22 @@
 
 using namespace android;
 
+// Called right before aborting by LOG_ALWAYS_FATAL. Print the pending exception.
+void abort_handler(const char* abort_message) {
+    ALOGE("About to abort the process...");
+
+    JNIEnv* env = NULL;
+    if (javaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        ALOGE("vm->GetEnv() failed");
+        return;
+    }
+    if (env->ExceptionOccurred() != NULL) {
+        ALOGE("Pending exception:");
+        env->ExceptionDescribe();
+    }
+    ALOGE("Aborting because: %s", abort_message);
+}
+
 JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
     javaVM = vm;
     JNIEnv* env = nullptr;
@@ -369,6 +385,8 @@
         return JNI_ERR;
     }
 
+    __android_log_set_aborter(abort_handler);
+
     init_android_graphics();
 
     // Configuration is stored as java System properties.
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 070d07c..5223798 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -18,6 +18,8 @@
 //#define LOG_NDEBUG 0
 
 #define LOG_TAG "AudioSystem-JNI"
+#include <android/binder_ibinder_jni.h>
+#include <android/binder_libbinder.h>
 #include <android/media/AudioVibratorInfo.h>
 #include <android/media/INativeSpatializerCallback.h>
 #include <android/media/ISpatializer.h>
@@ -25,6 +27,7 @@
 #include <android_media_audiopolicy.h>
 #include <android_os_Parcel.h>
 #include <audiomanager/AudioManager.h>
+#include <binder/IBinder.h>
 #include <jni.h>
 #include <media/AidlConversion.h>
 #include <media/AudioContainers.h>
@@ -150,13 +153,14 @@
 static jclass gAudioMixClass;
 static jmethodID gAudioMixCstor;
 static struct {
-    jfieldID    mRule;
-    jfieldID    mFormat;
-    jfieldID    mRouteFlags;
-    jfieldID    mDeviceType;
-    jfieldID    mDeviceAddress;
-    jfieldID    mMixType;
-    jfieldID    mCallbackFlags;
+    jfieldID mRule;
+    jfieldID mFormat;
+    jfieldID mRouteFlags;
+    jfieldID mDeviceType;
+    jfieldID mDeviceAddress;
+    jfieldID mMixType;
+    jfieldID mCallbackFlags;
+    jfieldID mToken;
 } gAudioMixFields;
 
 static jclass gAudioFormatClass;
@@ -2300,11 +2304,15 @@
     if (status != AUDIO_JAVA_SUCCESS) {
         return status;
     }
+    std::unique_ptr<AIBinder, decltype(&AIBinder_decStrong)> aiBinder(AIBinder_fromPlatformBinder(
+                                                                              nAudioMix.mToken),
+                                                                      &AIBinder_decStrong);
+    jobject jBinderToken = AIBinder_toJavaBinder(env, aiBinder.get());
 
     jstring deviceAddress = env->NewStringUTF(nAudioMix.mDeviceAddress.c_str());
     *jAudioMix = env->NewObject(gAudioMixClass, gAudioMixCstor, jAudioMixingRule, jAudioFormat,
                                 nAudioMix.mRouteFlags, nAudioMix.mCbFlags, nAudioMix.mDeviceType,
-                                deviceAddress);
+                                deviceAddress, jBinderToken);
     return AUDIO_JAVA_SUCCESS;
 }
 
@@ -2333,6 +2341,12 @@
     nAudioMix->mVoiceCommunicationCaptureAllowed =
             env->GetBooleanField(jRule, gAudioMixingRuleFields.mVoiceCommunicationCaptureAllowed);
 
+    jobject jToken = env->GetObjectField(jAudioMix, gAudioMixFields.mToken);
+
+    std::unique_ptr<AIBinder, decltype(&AIBinder_decStrong)>
+            aiBinder(AIBinder_fromJavaBinder(env, jToken), &AIBinder_decStrong);
+    nAudioMix->mToken = AIBinder_toPlatformBinder(aiBinder.get());
+
     jint status = convertAudioMixingRuleToNative(env, jRule, &(nAudioMix->mCriteria));
 
     env->DeleteLocalRef(jRule);
@@ -3659,9 +3673,10 @@
     jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
     gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
     if (audio_flags::audio_mix_test_api()) {
-        gAudioMixCstor = GetMethodIDOrDie(env, audioMixClass, "<init>",
-                                          "(Landroid/media/audiopolicy/AudioMixingRule;Landroid/"
-                                          "media/AudioFormat;IIILjava/lang/String;)V");
+        gAudioMixCstor =
+                GetMethodIDOrDie(env, audioMixClass, "<init>",
+                                 "(Landroid/media/audiopolicy/AudioMixingRule;Landroid/"
+                                 "media/AudioFormat;IIILjava/lang/String;Landroid/os/IBinder;)V");
     }
     gAudioMixFields.mRule = GetFieldIDOrDie(env, audioMixClass, "mRule",
                                                 "Landroid/media/audiopolicy/AudioMixingRule;");
@@ -3673,6 +3688,7 @@
                                                       "Ljava/lang/String;");
     gAudioMixFields.mMixType = GetFieldIDOrDie(env, audioMixClass, "mMixType", "I");
     gAudioMixFields.mCallbackFlags = GetFieldIDOrDie(env, audioMixClass, "mCallbackFlags", "I");
+    gAudioMixFields.mToken = GetFieldIDOrDie(env, audioMixClass, "mToken", "Landroid/os/IBinder;");
 
     jclass audioFormatClass = FindClassOrDie(env, "android/media/AudioFormat");
     gAudioFormatClass = MakeGlobalRefOrDie(env, audioFormatClass);
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 285dee3..b39d5cf 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -85,9 +85,24 @@
 
 ScopedLocalRef<jobject> android_view_MotionEvent_obtainAsCopy(JNIEnv* env,
                                                               const MotionEvent& event) {
-    std::unique_ptr<MotionEvent> destEvent = std::make_unique<MotionEvent>();
+    ScopedLocalRef<jobject> eventObj(env,
+                                     env->CallStaticObjectMethod(gMotionEventClassInfo.clazz,
+                                                                 gMotionEventClassInfo.obtain));
+    if (env->ExceptionCheck() || !eventObj.get()) {
+        ALOGE("An exception occurred while obtaining a motion event.");
+        LOGE_EX(env);
+        env->ExceptionClear();
+        return ScopedLocalRef<jobject>(env);
+    }
+
+    MotionEvent* destEvent = android_view_MotionEvent_getNativePtr(env, eventObj.get());
+    if (!destEvent) {
+        destEvent = new MotionEvent();
+        android_view_MotionEvent_setNativePtr(env, eventObj, destEvent);
+    }
+
     destEvent->copyFrom(&event, true);
-    return android_view_MotionEvent_obtainFromNative(env, std::move(destEvent));
+    return eventObj;
 }
 
 ScopedLocalRef<jobject> android_view_MotionEvent_obtainFromNative(
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 0938ce17..3ed9f49 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1965,7 +1965,7 @@
 
     // If this zygote isn't root, it won't be able to create a process group,
     // since the directory is owned by root.
-    if (!is_system_server && getuid() == 0) {
+    if (getuid() == 0) {
         const int rc = createProcessGroup(uid, getpid());
         if (rc != 0) {
             fail_fn(rc == -EROFS ? CREATE_ERROR("createProcessGroup failed, kernel missing "
diff --git a/core/proto/android/internal/protolog.proto b/core/proto/android/internal/protolog.proto
index fee7a87..9e205e2 100644
--- a/core/proto/android/internal/protolog.proto
+++ b/core/proto/android/internal/protolog.proto
@@ -27,7 +27,7 @@
     option (.android.msg_privacy).dest = DEST_LOCAL;
 
     /* log statement identifier, created from message string and log level. */
-    optional sfixed32 message_hash = 1;
+    optional sfixed32 message_hash_legacy = 1 [deprecated = true];
     /* log time, relative to the elapsed system time clock. */
     optional fixed64 elapsed_realtime_nanos = 2;
     /* string parameters passed to the log call. */
@@ -38,6 +38,9 @@
     repeated double double_params = 5 [packed=true];
     /* boolean parameters passed to the log call. */
     repeated bool boolean_params = 6 [packed=true];
+
+    /* log statement identifier, created from message string and log level. */
+    optional sfixed64 message_hash = 7;
 }
 
 /* represents a log file containing ProtoLog log entries.
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 4fc9b40..763d9ce 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -101,6 +101,7 @@
         optional SettingProto accessibility_magnification_two_finger_triple_tap_enabled = 53 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto qs_targets = 54 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto accessibility_pinch_to_zoom_anywhere_enabled = 55 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto accessibility_single_finger_panning_enabled = 56 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
     }
     optional Accessibility accessibility = 2;
diff --git a/core/proto/android/server/vibrator/vibratormanagerservice.proto b/core/proto/android/server/vibrator/vibratormanagerservice.proto
index db99e5b..9151958 100644
--- a/core/proto/android/server/vibrator/vibratormanagerservice.proto
+++ b/core/proto/android/server/vibrator/vibratormanagerservice.proto
@@ -79,11 +79,28 @@
     repeated int32 delays = 2;
 }
 
+// Next Tag: 5
 message VibrationAttributesProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
     optional int32 usage = 1;
     optional int32 audio_usage = 2;
     optional int32 flags = 3;
+    optional int32 category = 4;
+}
+
+// Next Tag: 4
+message VibrationParamProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+    optional VibrationScaleParamProto scale = 1;
+    optional int64 create_time = 2;
+    optional bool is_from_request = 3;
+}
+
+// Next Tag: 3
+message VibrationScaleParamProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+    optional int32 types_mask = 1;
+    optional float scale = 2;
 }
 
 // Next Tag: 9
@@ -132,16 +149,19 @@
     }
 }
 
-// Next Tag: 25
+// Next Tag: 29
 message VibratorManagerServiceDumpProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
     repeated int32 vibrator_ids = 1;
     optional VibrationProto current_vibration = 2;
     optional bool is_vibrating = 3;
+    optional int32 is_vibrator_controller_registered = 27;
     optional VibrationProto current_external_vibration = 4;
     optional bool vibrator_under_external_control = 5;
     optional bool low_power_mode = 6;
     optional bool vibrate_on = 24;
+    optional bool keyboard_vibration_on = 25;
+    optional int32 default_vibration_amplitude = 26;
     optional int32 alarm_intensity = 18;
     optional int32 alarm_default_intensity = 19;
     optional int32 haptic_feedback_intensity = 7;
@@ -158,5 +178,6 @@
     repeated VibrationProto previous_notification_vibrations = 14;
     repeated VibrationProto previous_alarm_vibrations = 15;
     repeated VibrationProto previous_vibrations = 16;
-    repeated VibrationProto previous_external_vibrations = 17;
+    repeated VibrationParamProto previous_vibration_params = 28;
+    reserved 17; // prev previous_external_vibrations
 }
\ No newline at end of file
diff --git a/core/res/Android.bp b/core/res/Android.bp
index 277824c..e2e419f 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -159,7 +159,7 @@
         "android.content.pm.flags-aconfig",
         "android.provider.flags-aconfig",
         "camera_platform_flags",
-        "com.android.net.flags-aconfig",
+        "android.net.platform.flags-aconfig",
         "com.android.window.flags.window-aconfig",
     ],
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8720f94..ba9751f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2281,7 +2281,7 @@
     <!-- @SystemApi @hide Allows changing Thread network state and access to Thread network
         credentials such as Network Key and PSKc.
         <p>Not for use by third-party applications.
-        @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") -->
+        @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") -->
     <permission android:name="android.permission.THREAD_NETWORK_PRIVILEGED"
                 android:protectionLevel="signature|privileged" />
 
@@ -2331,12 +2331,12 @@
     <!-- Allows system apps to call methods to register itself as a mDNS offload engine.
         <p>Not for use by third-party or privileged applications.
         @SystemApi
-        @FlaggedApi("com.android.net.flags.register_nsd_offload_engine")
+        @FlaggedApi("android.net.platform.flags.register_nsd_offload_engine")
         @hide This should only be used by system apps.
     -->
     <permission android:name="android.permission.REGISTER_NSD_OFFLOAD_ENGINE"
         android:protectionLevel="signature"
-        android:featureFlag="com.android.net.flags.register_nsd_offload_engine" />
+        android:featureFlag="android.net.platform.flags.register_nsd_offload_engine" />
 
     <!-- ======================================= -->
     <!-- Permissions for short range, peripheral networks -->
@@ -3629,7 +3629,7 @@
 
     <!-- Allows an application to set policy related to <a
     href="https://www.threadgroup.org">Thread</a> network.
-        @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled")
+        @FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled")
     -->
     <permission android:name="android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK"
                 android:protectionLevel="internal|role" />
@@ -7986,7 +7986,7 @@
         @hide
       -->
     <permission android:name="android.permission.GET_APP_METADATA"
-                android:protectionLevel="signature|installer" />
+                android:protectionLevel="signature|installer|verifier" />
 
     <!-- @hide @SystemApi Allows an application to stage HealthConnect's remote data so that
          HealthConnect can later integrate it. -->
@@ -8621,6 +8621,10 @@
                  android:permission="android.permission.BIND_JOB_SERVICE">
         </service>
 
+        <service android:name="com.android.system.virtualmachine.SecretkeeperJobService"
+                 android:permission="android.permission.BIND_JOB_SERVICE">
+        </service>
+
         <service android:name="com.android.server.PruneInstantAppsJobService"
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
diff --git a/core/res/res/drawable/pointer_wait_vector.xml b/core/res/res/drawable/pointer_wait_vector.xml
new file mode 100644
index 0000000..4de0690
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
+  <item android:drawable="@drawable/pointer_wait_vector_0" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_1" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_2" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_3" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_4" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_5" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_6" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_7" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_8" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_9" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_10" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_11" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_12" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_13" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_14" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_15" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_16" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_17" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_18" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_19" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_20" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_21" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_22" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_23" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_24" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_25" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_26" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_27" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_28" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_29" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_30" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_31" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_32" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_33" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_34" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_35" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_36" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_37" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_38" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_39" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_40" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_41" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_42" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_43" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_44" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_45" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_46" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_47" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_48" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_49" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_50" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_51" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_52" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_53" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_54" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_55" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_56" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_57" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_58" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_59" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_60" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_61" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_62" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_63" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_64" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_65" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_66" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_67" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_68" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_69" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_70" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_71" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_72" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_73" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_74" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_75" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_76" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_77" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_78" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_79" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_80" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_81" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_82" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_83" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_84" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_85" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_86" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_87" android:duration="16"/>
+</animation-list>
diff --git a/core/res/res/drawable/pointer_wait_vector_0.xml b/core/res/res/drawable/pointer_wait_vector_0.xml
new file mode 100644
index 0000000..4bfbc9f
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_0.xml
@@ -0,0 +1,27 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.116,18.654a1.78,1.78 0,1 0,0.061 3.561,1.78 1.78,0 0,0 -0.061,-3.561m-7.194,-1.73a1.781,1.781 0,1 0,2.594 2.441,1.781 1.781,0 0,0 -2.594,-2.441"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.294,7.294a1.78,1.78 0,1 0,-2.517 -2.519,1.78 1.78,0 0,0 2.517,2.519"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.225,7.294a1.78,1.78 0,1 0,-2.517 -2.519,1.78 1.78,0 0,0 2.517,2.519"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.436,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.747,16.665a1.78,1.78 0,1 0,2.539 2.497,1.78 1.78,0 0,0 -2.539,-2.497"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_1.xml b/core/res/res/drawable/pointer_wait_vector_1.xml
new file mode 100644
index 0000000..bab91e1
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_1.xml
@@ -0,0 +1,21 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.174,18.653a1.782,1.782 0,1 0,0.094 3.562,1.782 1.782,0 0,0 -0.094,-3.562m-7.187,-1.637a1.782,1.782 0,1 0,2.627 2.407,1.782 1.782,0 0,0 -2.627,-2.407"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.294,7.294a1.78,1.78 0,1 0,-2.517 -2.519,1.78 1.78,0 0,0 2.517,2.519"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.225,7.294a1.78,1.78 0,1 0,-2.517 -2.519,1.78 1.78,0 0,0 2.517,2.519m1.203,2.888a1.78,1.78 0,1 0,0.016 3.562,1.78 1.78,0 1,0 -0.016,-3.562m-3.641,6.441a1.782,1.782 0,1 0,2.564 2.475,1.782 1.782,0 0,0 -2.564,-2.475"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_10.xml b/core/res/res/drawable/pointer_wait_vector_10.xml
new file mode 100644
index 0000000..ae3e360
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_10.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.028,20.374m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.952,18.76m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12.066m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.957,6.113m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.779,3.566m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.7,5.78m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.42,11.485m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.462,17.423m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_11.xml b/core/res/res/drawable/pointer_wait_vector_11.xml
new file mode 100644
index 0000000..d2c014d
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_11.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.101,20.364m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.101,18.868m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12.074m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.931,6.139m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.706,3.569m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.646,5.731m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.41,11.338m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.509,17.366m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_12.xml b/core/res/res/drawable/pointer_wait_vector_12.xml
new file mode 100644
index 0000000..e9a36c0
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_12.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.247,20.344m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.222,18.953m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.564,12.147m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.88,6.193m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.632,3.571m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.591,5.681m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.404,11.265m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.602,17.252m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_13.xml b/core/res/res/drawable/pointer_wait_vector_13.xml
new file mode 100644
index 0000000..5800f39
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_13.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.392,20.321m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.344,19.035m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.565,12.184m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.83,6.246m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.559,3.575m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.535,5.633m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.39,11.118m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.693,17.136m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_14.xml b/core/res/res/drawable/pointer_wait_vector_14.xml
new file mode 100644
index 0000000..3566aaf
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_14.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.537,20.295m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.467,19.115m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.567,12.258m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.755,6.327m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.485,3.579m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.423,5.537m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.386,11.082m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.759,17.048m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_15.xml b/core/res/res/drawable/pointer_wait_vector_15.xml
new file mode 100644
index 0000000..c995faf
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_15.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.682,20.267m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.718,19.269m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.568,12.295m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.73,6.355m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.412,3.584m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.367,5.49m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.369,10.935m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.847,16.929m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_16.xml b/core/res/res/drawable/pointer_wait_vector_16.xml
new file mode 100644
index 0000000..1793282
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_16.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.826,20.237m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.846,19.343m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.57,12.331m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.706,6.382m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.338,3.589m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.31,5.444m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.354,10.826m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.91,16.839m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_17.xml b/core/res/res/drawable/pointer_wait_vector_17.xml
new file mode 100644
index 0000000..59772f5
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_17.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.969,20.204m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.974,19.414m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.571,12.368m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.681,6.41m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.191,3.602m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.194,5.352m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.333,10.68m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.994,16.718m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_18.xml b/core/res/res/drawable/pointer_wait_vector_18.xml
new file mode 100644
index 0000000..1bbb242
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_18.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M14.184,20.149m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.236,19.55m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.575,12.442m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.585,6.521m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.118,3.61m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.136,5.307m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.315,10.571m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.075,16.595m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_19.xml b/core/res/res/drawable/pointer_wait_vector_19.xml
new file mode 100644
index 0000000..b8e0dd5
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_19.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M14.325,20.11m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.434,19.646m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.581,12.552m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.537,6.577m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.972,3.626m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.959,5.175m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.282,10.39m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.193,16.408m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_2.xml b/core/res/res/drawable/pointer_wait_vector_2.xml
new file mode 100644
index 0000000..5c4606f
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_2.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.331,20.43m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.355,18.269m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.035m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.435,11.89m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.094,17.834m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_20.xml b/core/res/res/drawable/pointer_wait_vector_20.xml
new file mode 100644
index 0000000..b3ac2dab
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_20.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M14.607,20.024m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.703,19.766m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.592,12.699m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.49,6.634m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.899,3.636m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.899,5.132m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.252,10.246m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.269,16.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_21.xml b/core/res/res/drawable/pointer_wait_vector_21.xml
new file mode 100644
index 0000000..884476e
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_21.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M14.816,19.953m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.908,19.849m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.589,12.662m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.443,6.691m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.753,3.656m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.718,5.006m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.22,10.102m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.414,16.025m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_22.xml b/core/res/res/drawable/pointer_wait_vector_22.xml
new file mode 100644
index 0000000..20660ca
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_22.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M15.092,19.849m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.184,19.952m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.617,12.955m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.352,6.806m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.608,3.679m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.595,4.925m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.149,9.816m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.483,15.896m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_23.xml b/core/res/res/drawable/pointer_wait_vector_23.xml
new file mode 100644
index 0000000..6b594ee7
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_23.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M15.296,19.766m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.533,20.068m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.609,12.882m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.262,6.923m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.463,3.705m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.471,4.845m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.11,9.675m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.614,15.632m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_24.xml b/core/res/res/drawable/pointer_wait_vector_24.xml
new file mode 100644
index 0000000..a35203e
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_24.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M15.632,19.615m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.816,20.149m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.626,13.028m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.175,7.041m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.318,3.733m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.346,4.769m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.046,9.463m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.677,15.498m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_25.xml b/core/res/res/drawable/pointer_wait_vector_25.xml
new file mode 100644
index 0000000..df8549a
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_25.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M15.896,19.483m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.174,20.236m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.645,13.174m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.089,7.161m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.174,3.763m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.219,4.694m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.977,9.253m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.794,15.228m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_26.xml b/core/res/res/drawable/pointer_wait_vector_26.xml
new file mode 100644
index 0000000..0abb7d41
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_26.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M16.154,19.343m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.535,20.308m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.667,13.32m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.006,7.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.959,3.814m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.961,4.551m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.902,9.045m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.902,14.955m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_27.xml b/core/res/res/drawable/pointer_wait_vector_27.xml
new file mode 100644
index 0000000..bde2425
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_27.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M16.471,19.155m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.972,20.374m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.691,13.465m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.885,7.467m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.817,3.851m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.831,4.483m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.85,8.908m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.023,14.607m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_28.xml b/core/res/res/drawable/pointer_wait_vector_28.xml
new file mode 100644
index 0000000..19cb410
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_28.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M16.778,18.953m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.411,20.416m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.718,13.61m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.807,7.592m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.604,3.911m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.566,4.354m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.677,8.502m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.109,14.325m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_29.xml b/core/res/res/drawable/pointer_wait_vector_29.xml
new file mode 100644
index 0000000..5d6776f
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_29.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M17.136,18.693m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.926,20.436m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.748,13.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.731,7.718m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.463,3.954m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.365,4.263m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.55,8.236m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.203,13.969m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_3.xml b/core/res/res/drawable/pointer_wait_vector_3.xml
new file mode 100644
index 0000000..8a19401
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_3.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.368,20.429m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.437,18.343m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.94,6.009m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.435,11.853m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.119,17.807m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_30.xml b/core/res/res/drawable/pointer_wait_vector_30.xml
new file mode 100644
index 0000000..56dcdc2
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_30.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M17.479,18.415m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12.441,20.425m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.796,13.969m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.586,7.974m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.184,4.047m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.092,4.151m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.414,7.975m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.281,13.61m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_31.xml b/core/res/res/drawable/pointer_wait_vector_31.xml
new file mode 100644
index 0000000..5687a9b
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_31.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M17.807,18.12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.028,20.373m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.832,14.112m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.517,8.104m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.908,4.15m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.817,4.047m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.269,7.718m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.344,13.247m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_32.xml b/core/res/res/drawable/pointer_wait_vector_32.xml
new file mode 100644
index 0000000..cb626e4
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_32.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M18.17,17.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.61,20.281m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.87,14.254m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.417,8.302m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.704,4.234m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.537,3.954m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.076,7.405m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.397,12.809m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_33.xml b/core/res/res/drawable/pointer_wait_vector_33.xml
new file mode 100644
index 0000000..052f973
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_33.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M18.51,17.366m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.183,20.149m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.954,14.537m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.323,8.501m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.435,4.354m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.184,3.851m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.868,7.101m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.428,12.368m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_34.xml b/core/res/res/drawable/pointer_wait_vector_34.xml
new file mode 100644
index 0000000..9e665756
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_34.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M18.911,16.839m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.885,19.928m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.999,14.677m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.206,8.771m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.17,4.483m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.826,3.764m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.603,6.748m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.433,11.779m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_35.xml b/core/res/res/drawable/pointer_wait_vector_35.xml
new file mode 100644
index 0000000..1d063fc
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_35.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M19.232,16.345m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.566,19.646m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.098,14.955m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.098,9.045m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.846,4.657m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.465,3.692m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.27,6.355m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.41,11.338m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_36.xml b/core/res/res/drawable/pointer_wait_vector_36.xml
new file mode 100644
index 0000000..db0ad1c
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_36.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M19.583,15.698m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.345,19.232m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.205,15.229m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.999,9.323m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.592,4.807m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.028,3.626m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.035m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.344,10.753m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_37.xml b/core/res/res/drawable/pointer_wait_vector_37.xml
new file mode 100644
index 0000000..ee944a6
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_37.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M19.876,15.023m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.077,18.738m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.323,15.499m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.911,9.604m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.221,5.047m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12.589,3.584m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.59,5.681m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.236,10.174m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_38.xml b/core/res/res/drawable/pointer_wait_vector_38.xml
new file mode 100644
index 0000000..a347a36
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_38.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M20.129,14.255m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.861,18.069m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.45,15.764m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.796,10.031m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.864,5.307m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12.147,3.565m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.136,5.307m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.046,9.463m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_39.xml b/core/res/res/drawable/pointer_wait_vector_39.xml
new file mode 100644
index 0000000..2c86f0d
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_39.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M20.321,13.392m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.557,17.309m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.586,16.026m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.705,10.462m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.521,5.585m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.559,3.575m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.657,4.965m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.766,8.704m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_4.xml b/core/res/res/drawable/pointer_wait_vector_4.xml
new file mode 100644
index 0000000..a6690c0
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_4.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.441,20.425m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.493,18.391m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.914,5.983m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.433,11.772m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.17,17.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_40.xml b/core/res/res/drawable/pointer_wait_vector_40.xml
new file mode 100644
index 0000000..953fdc1
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_40.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M20.428,12.368m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.232,16.345m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.731,16.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.656,10.753m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.193,5.88m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.972,3.626m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.026,4.586m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.449,8.039m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_41.xml b/core/res/res/drawable/pointer_wait_vector_41.xml
new file mode 100644
index 0000000..a1b17fa
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_41.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M20.41,11.338m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.766,15.296m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.924,16.595m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.602,11.191m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.83,6.246m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.39,3.719m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.364,4.263m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.994,7.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_42.xml b/core/res/res/drawable/pointer_wait_vector_42.xml
new file mode 100644
index 0000000..4de9b8d
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_42.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M20.244,10.21m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.14,14.219m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.153,16.929m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.571,11.632m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.49,6.634m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.817,3.851m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.677,4m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.367,6.465m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_43.xml b/core/res/res/drawable/pointer_wait_vector_43.xml
new file mode 100644
index 0000000..38187fe
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_43.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M19.94,9.149m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.365,13.101m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.397,17.252m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.566,12.221m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.089,7.161m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.115,4.072m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.826,3.763m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.645,5.73m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_44.xml b/core/res/res/drawable/pointer_wait_vector_44.xml
new file mode 100644
index 0000000..890ba7e
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_44.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M19.466,8.072m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.436,12.073m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.73,17.645m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.589,12.662m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.768,7.655m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.368,4.385m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12.882,3.61m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.839,5.089m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_45.xml b/core/res/res/drawable/pointer_wait_vector_45.xml
new file mode 100644
index 0000000..309ac08
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_45.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M18.847,7.071m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.382,11.045m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.139,18.069m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.656,13.247m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.417,8.302m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.592,4.807m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.853,3.565m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.83,4.483m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_46.xml b/core/res/res/drawable/pointer_wait_vector_46.xml
new file mode 100644
index 0000000..5a9bf70
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_46.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M18.195,6.273m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.237,10.174m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.465,18.367m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.797,13.969m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.124,8.977m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.864,5.307m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.826,3.646m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.747,4.023m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_47.xml b/core/res/res/drawable/pointer_wait_vector_47.xml
new file mode 100644
index 0000000..0068f27
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_47.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M17.451,5.561m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.046,9.463m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.922,18.738m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.954,14.537m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.851,9.817m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.087,5.983m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.675,3.89m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.61,3.718m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_48.xml b/core/res/res/drawable/pointer_wait_vector_48.xml
new file mode 100644
index 0000000..6ece990
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_48.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M16.748,5.026m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.822,8.84m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.405,19.076m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.205,15.229m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.667,10.68m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.397,6.748m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.569,4.293m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12.588,3.584m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_49.xml b/core/res/res/drawable/pointer_wait_vector_49.xml
new file mode 100644
index 0000000..d444389
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_49.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M16.09,4.621m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.583,8.302m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.974,19.414m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.586,16.025m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.571,11.632m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.768,7.655m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.655,4.768m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.558,3.575m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_5.xml b/core/res/res/drawable/pointer_wait_vector_5.xml
new file mode 100644
index 0000000..4952fe5
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_5.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.515,20.421m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.577,18.463m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.877,5.947m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.433,11.779m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.22,17.7m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_50.xml b/core/res/res/drawable/pointer_wait_vector_50.xml
new file mode 100644
index 0000000..a85155f
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_50.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M15.499,4.323m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.343,7.846m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.636,19.737m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.047,16.778m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.589,12.662m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.234,8.704m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.634,5.49m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.608,3.679m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_51.xml b/core/res/res/drawable/pointer_wait_vector_51.xml
new file mode 100644
index 0000000..95b4aaa
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_51.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M14.885,4.072m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.155,7.529m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.393,20.024m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.585,17.479m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.748,13.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.851,9.817m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.88,6.193m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.816,3.851m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_52.xml b/core/res/res/drawable/pointer_wait_vector_52.xml
new file mode 100644
index 0000000..34619b5
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_52.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M14.396,3.911m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.953,7.221m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.246,20.252m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.3,18.22m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.072,14.885m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.636,10.899m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.307,6.864m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.114,4.072m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_53.xml b/core/res/res/drawable/pointer_wait_vector_53.xml
new file mode 100644
index 0000000..926b639
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_53.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.969,3.797m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.782,6.982m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.118,20.39m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.221,18.953m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.551,15.961m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.564,11.927m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.807,7.592m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.568,4.293m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_54.xml b/core/res/res/drawable/pointer_wait_vector_54.xml
new file mode 100644
index 0000000..c51851fc
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_54.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.61,3.718m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.603,6.748m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12.147,20.435m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.17,19.517m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.132,16.899m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.618,12.955m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.45,8.236m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.104,4.517m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_55.xml b/core/res/res/drawable/pointer_wait_vector_55.xml
new file mode 100644
index 0000000..cdf435f
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_55.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.247,3.656m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.463,6.577m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.247,20.344m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.253,19.977m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.83,17.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.748,13.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.178,8.84m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.686,4.749m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_56.xml b/core/res/res/drawable/pointer_wait_vector_56.xml
new file mode 100644
index 0000000..1528711
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_56.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.028,3.626m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.319,6.41m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.325,20.11m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.39,20.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.521,18.415m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.954,14.537m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.976,9.393m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.405,4.924m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_57.xml b/core/res/res/drawable/pointer_wait_vector_57.xml
new file mode 100644
index 0000000..1715db1
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_57.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.772,3.599m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.22,6.3m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.431,19.707m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.411,20.416m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.282,18.994m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.178,15.16m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.851,9.817m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.041,5.175m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_58.xml b/core/res/res/drawable/pointer_wait_vector_58.xml
new file mode 100644
index 0000000..83aec4b
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_58.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.589,3.584m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.12,6.193m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.471,19.155m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12.442,20.425m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.974,19.414m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.417,15.698m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.748,10.246m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.864,5.307m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_59.xml b/core/res/res/drawable/pointer_wait_vector_59.xml
new file mode 100644
index 0000000..2e5e472
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_59.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.442,3.575m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.069,6.139m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.309,18.556m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.465,20.308m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.568,19.707m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.657,16.154m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.679,10.608m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.634,5.49m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_6.xml b/core/res/res/drawable/pointer_wait_vector_6.xml
new file mode 100644
index 0000000..d4f57af
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_6.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.588,20.416m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.633,18.51m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.926,3.564m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.861,5.931m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.431,11.706m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.269,17.645m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_60.xml b/core/res/res/drawable/pointer_wait_vector_60.xml
new file mode 100644
index 0000000..4f25767
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_60.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.294,3.569m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.069,6.139m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.12,17.807m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.183,20.149m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.115,19.928m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.845,16.471m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.646,10.826m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.465,5.633m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_61.xml b/core/res/res/drawable/pointer_wait_vector_61.xml
new file mode 100644
index 0000000..7e06db4
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_61.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.147,3.565m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.017,6.087m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.738,17.077m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.885,19.928m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.604,20.089m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.047,16.779m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.61,11.118m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.355,5.73m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_62.xml b/core/res/res/drawable/pointer_wait_vector_62.xml
new file mode 100644
index 0000000..b3d0541
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_62.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.074,3.564m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.231,16.345m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.432,19.707m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.102,20.22m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.307,17.136m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.584,11.411m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.246,5.83m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_63.xml b/core/res/res/drawable/pointer_wait_vector_63.xml
new file mode 100644
index 0000000..ee09c25
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_63.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.583,15.698m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.961,19.449m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.39,20.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.397,17.252m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.575,11.558m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.193,5.88m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_64.xml b/core/res/res/drawable/pointer_wait_vector_64.xml
new file mode 100644
index 0000000..e87f94f
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_64.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.822,15.16m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.345,19.232m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.826,20.354m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.537,17.423m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.571,11.632m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.139,5.931m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_65.xml b/core/res/res/drawable/pointer_wait_vector_65.xml
new file mode 100644
index 0000000..b8407c44
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_65.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.023,14.607m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.718,18.994m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.972,20.374m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.681,17.59m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.569,11.706m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.087,5.983m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_66.xml b/core/res/res/drawable/pointer_wait_vector_66.xml
new file mode 100644
index 0000000..7e2448d
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_66.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.149,14.184m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.959,18.825m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.265,20.405m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.78,17.7m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.565,11.853m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_67.xml b/core/res/res/drawable/pointer_wait_vector_67.xml
new file mode 100644
index 0000000..615ac04
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_67.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.252,13.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.194,18.648m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.412,20.416m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.88,17.807m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_68.xml b/core/res/res/drawable/pointer_wait_vector_68.xml
new file mode 100644
index 0000000..0ba4634
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_68.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.308,13.465m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.366,18.51m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.632,20.429m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.931,17.861m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_69.xml b/core/res/res/drawable/pointer_wait_vector_69.xml
new file mode 100644
index 0000000..efa90bf
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_69.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.354,13.174m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.535,18.367m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.706,20.432m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.931,17.86m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_7.xml b/core/res/res/drawable/pointer_wait_vector_7.xml
new file mode 100644
index 0000000..86d571a
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_7.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.661,20.411m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.69,18.556m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.024,6.045m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.889,3.564m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.808,5.88m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.428,11.632m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.318,17.59m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_70.xml b/core/res/res/drawable/pointer_wait_vector_70.xml
new file mode 100644
index 0000000..4e58af5
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_70.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.39,12.882m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.645,18.27m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.853,20.435m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_71.xml b/core/res/res/drawable/pointer_wait_vector_71.xml
new file mode 100644
index 0000000..5a53434
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_71.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.416,12.589m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.754,18.17m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.853,20.435m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_72.xml b/core/res/res/drawable/pointer_wait_vector_72.xml
new file mode 100644
index 0000000..40fb5d3
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_72.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.425,12.442m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.807,18.12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_73.xml b/core/res/res/drawable/pointer_wait_vector_73.xml
new file mode 100644
index 0000000..933cc6a
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_73.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.429,12.368m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.861,18.069m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_74.xml b/core/res/res/drawable/pointer_wait_vector_74.xml
new file mode 100644
index 0000000..6c7fef2
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_74.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.431,12.294m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_75.xml b/core/res/res/drawable/pointer_wait_vector_75.xml
new file mode 100644
index 0000000..24e64e3
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_75.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.435,12.147m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_76.xml b/core/res/res/drawable/pointer_wait_vector_76.xml
new file mode 100644
index 0000000..2ede57d
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_76.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.436,12.073m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_77.xml b/core/res/res/drawable/pointer_wait_vector_77.xml
new file mode 100644
index 0000000..71f811a
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_77.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.436,12.037m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_78.xml b/core/res/res/drawable/pointer_wait_vector_78.xml
new file mode 100644
index 0000000..e2d56c6
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_78.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.437,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_79.xml b/core/res/res/drawable/pointer_wait_vector_79.xml
new file mode 100644
index 0000000..e2d56c6
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_79.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.437,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_8.xml b/core/res/res/drawable/pointer_wait_vector_8.xml
new file mode 100644
index 0000000..ebac749
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_8.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.808,20.398m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.806,18.648m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.008,6.061m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.853,3.565m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.754,5.83m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.425,11.558m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.367,17.535m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_80.xml b/core/res/res/drawable/pointer_wait_vector_80.xml
new file mode 100644
index 0000000..40fb5d3
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_80.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.425,12.442m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.807,18.12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_81.xml b/core/res/res/drawable/pointer_wait_vector_81.xml
new file mode 100644
index 0000000..933cc6a
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_81.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.429,12.368m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.861,18.069m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_82.xml b/core/res/res/drawable/pointer_wait_vector_82.xml
new file mode 100644
index 0000000..6c7fef2
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_82.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.431,12.294m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_83.xml b/core/res/res/drawable/pointer_wait_vector_83.xml
new file mode 100644
index 0000000..24e64e3
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_83.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.435,12.147m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_84.xml b/core/res/res/drawable/pointer_wait_vector_84.xml
new file mode 100644
index 0000000..2ede57d
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_84.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.436,12.073m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_85.xml b/core/res/res/drawable/pointer_wait_vector_85.xml
new file mode 100644
index 0000000..71f811a
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_85.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.436,12.037m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_86.xml b/core/res/res/drawable/pointer_wait_vector_86.xml
new file mode 100644
index 0000000..e2d56c6
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_86.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.437,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_87.xml b/core/res/res/drawable/pointer_wait_vector_87.xml
new file mode 100644
index 0000000..e2d56c6
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_87.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.437,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_9.xml b/core/res/res/drawable/pointer_wait_vector_9.xml
new file mode 100644
index 0000000..d46dfa3
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_9.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.881,20.39m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.864,18.693m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12.052m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.983,6.087m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.816,3.565m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.754,5.83m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.423,11.522m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.415,17.479m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_icon.xml b/core/res/res/drawable/pointer_wait_vector_icon.xml
new file mode 100644
index 0000000..45d371e
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_wait_vector"
+    android:hotSpotX="12dp"
+    android:hotSpotY="12dp" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 6cd2c4e..73877b8 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Hervat werkapps?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Hervat"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Noodgeval"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Stel ’n skermslot"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Stel skermslot"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Stel ’n skermslot op dié toestel om jou privaat ruimte te gebruik"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Program is nie beskikbaar nie"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is nie op die oomblik beskikbaar nie."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> is nie beskikbaar nie"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index b485b4b..e513a07 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"የሥራ መተግበሪያዎች ከቆሙበት ይቀጥሉ?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"ከቆመበት ቀጥል"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ድንገተኛ አደጋ"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"ማያ ገጽ መቆለፊያን ያቀናብሩ"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ማያ ገጽ መቆለፊያውን ያቀናብሩ"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"የግል ቦታዎን ለመጠቀም፣ በዚህ መሣሪያ ላይ ማያ ገጽ መቆለፊያን ያቀናብሩ"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> አይገኝም"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index b12c115..95fa5db 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1990,6 +1990,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"أتريد إعادة تفعيل تطبيقات العمل؟"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"إعادة التفعيل"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"الطوارئ"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"ضبط قفل شاشة"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ضبط قفل الشاشة"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"لاستخدام مساحتك الخاصة، يجب ضبط قفل شاشة على هذا الجهاز."</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"تطبيق <xliff:g id="ACTIVITY">%1$s</xliff:g> غير متاح"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 01705ad..9fb7149 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"কাম সম্পৰ্কীয় এপ্ আনপজ কৰিবনে?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"আনপজ কৰক"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"জৰুৰীকালীন"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"এটা স্ক্ৰীন লক ছেট কৰক"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"স্ক্ৰীন লক ছেট কৰা"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"আপোনাৰ প্ৰাইভেট স্পেচ ব্যৱহাৰ কৰিবলৈ এই ডিভাইচটোত স্ক্ৰীন লক ছেট কৰক"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> উপলব্ধ নহয়"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 4ed5f5e..5c3c652 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"İş tətbiqi üzrə pauza bitsin?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Pauzanı bitirin"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Fövqəladə hal"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ekran kilidi ayarlayın"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ekran kilidi ayarlayın"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Bu cihazda ekran kilidi ayarlamaqla şəxsi sahədən istifadə edin"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Tətbiq əlçatan deyil"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> hazırda əlçatan deyil."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> əlçatan deyil"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index b31dca4..bda2a55 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1987,6 +1987,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Uključiti poslovne aplikacije?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Ponovo aktiviraj"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Hitan slučaj"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Podesite zaključavanje ekrana"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Podesi zaključavanje ekrana"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Da biste koristili privatni prostor, podesite zaključavanje ekrana na ovom uređaju"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno nije dostupna."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – nije dostupno"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 2bd78e9..38b8e43 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1988,6 +1988,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Уключыць працоўныя праграмы?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Уключыць"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Экстранны выпадак"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Наладзьце блакіроўку экрана"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Наладзіць блакіроўку экрана"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Каб выкарыстоўваць прыватную прастору, на прыладзе неабходна наладзіць блакіроўку экрана"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недаступна: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index dc1e92c..77933ba 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Отмяна на паузата за служ. прил.?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Отмяна на паузата"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Спешен случай"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Настройте заключване на екрана"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Заключване на екрана"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"За да ползвате частното си пространство, настройте заключване на екрана"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> не е налице"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 5dbaad6..b7c7399 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"অফিসের অ্যাপ আনপজ করতে চান?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"আনপজ করুন"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"জরুরি"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"\'স্ক্রিন লক\' সেট-আপ করুন"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"\'স্ক্রিন লক\' ফিচার সেট করুন"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"নিজের প্রাইভেট স্পেস ব্যবহার করতে এই ডিভাইসে \'স্ক্রিন লক\' সেট করুন"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> উপলভ্য নেই"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 838a2db..90af630 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1987,6 +1987,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Pokrenuti poslovne aplikacije?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Ponovo pokreni"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Hitan slučaj"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Postavite zaključavanje ekrana"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Postavite zaključavanje ekrana"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Da koristite privatni prostor, postavite zaklj. ekr. na ur."</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno nije dostupna."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"Nedostupno: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index feb67c4..f20d334 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1987,6 +1987,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Reactivar les apps de treball?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Reactiva"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergència"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Defineix un bloqueig de pantalla"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Defineix un bloqueig de pantalla"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Per utilitzar l\'espai privat, defineix un bloq. de pantalla"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"L\'aplicació no està disponible"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"Ara mateix, <xliff:g id="APP_NAME">%1$s</xliff:g> no està disponible."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no està disponible"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 1c0529a..d603890 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1988,6 +1988,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Zrušit pozastavení pracovních aplikací?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Zrušit pozastavení"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Stav nouze"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Nastavení zámku obrazovky"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Nastavit zámek obrazovky"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Pokud chcete používat soukromý prostor, nastavte na tomto zařízení zámek obrazovky"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Aplikace není k dispozici"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> v tuto chvíli není k dispozici."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> není k dispozici"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 3010dc7..fc73fa7 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -522,7 +522,7 @@
     <string name="permdesc_vibrate" msgid="8733343234582083721">"Tillader, at appen kan administrere vibratoren."</string>
     <string name="permdesc_vibrator_state" msgid="7050024956594170724">"Tillader, at appen bruger vibration."</string>
     <string name="permlab_callPhone" msgid="1798582257194643320">"ringe direkte op til telefonnumre"</string>
-    <string name="permdesc_callPhone" msgid="7892422187827695656">"Tillader, at appen kan ringe til telefonnumre uden din indgriben. Dette kan resultere i uventede debiteringer eller opkald. Vær opmærksom på, at dette ikke giver appen tilladelse til at ringe til alarmnumre. Skadelige apps kan koste dig penge ved at foretage opkald uden din bekræftelse eller ved at ringe op til operatørkoder, hvilket resulterer i, at indgående opkald automatisk viderestilles til et andet nummer."</string>
+    <string name="permdesc_callPhone" msgid="7892422187827695656">"Tillader, at appen kan ringe til telefonnumre uden din indgriben. Dette kan resultere i uventede opkrævninger eller opkald. Vær opmærksom på, at dette ikke giver appen tilladelse til at ringe til alarmnumre. Skadelige apps kan koste dig penge ved at foretage opkald uden din bekræftelse eller ved at ringe op til operatørkoder, hvilket resulterer i, at indgående opkald automatisk viderestilles til et andet nummer."</string>
     <string name="permlab_accessImsCallService" msgid="442192920714863782">"få adgang til chat-opkaldstjeneste"</string>
     <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"Tillader, at appen kan bruge chat-tjenesten til at foretage opkald, uden du gør noget."</string>
     <string name="permlab_readPhoneState" msgid="8138526903259297969">"læse telefonens status og identitet"</string>
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Vil du genoptage arbejdsapps?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Genoptag"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Nødopkald"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Konfigurer en skærmlås"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Konfigurer skærmlås"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Konfigurer en skærmlås på enheden for at bruge dit private område"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Appen er ikke tilgængelig"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ikke tilgængelig lige nu."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> er ikke understøttet"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 803b967..9faf515 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -477,9 +477,9 @@
     <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"Ermöglicht der App, die Anrufliste deines Android TV-Geräts zu ändern, einschließlich der Daten über ein- und ausgehende Anrufe. Du solltest wissen, dass dies von schädlichen Apps genutzt werden kann, um Einträge in der Anrufliste zu löschen oder zu ändern."</string>
     <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"Ermöglicht der App, die Anrufliste deines Telefons zu ändern, einschließlich der Daten über ein- und ausgehende Anrufe. Schädliche Apps können so die Einträge in der Anrufliste löschen oder sie ändern."</string>
     <string name="permlab_bodySensors" msgid="662918578601619569">"Zugriff auf Daten des Körpersensors, etwa Herzfrequenz, wenn in Benutzung"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="7652650410295512140">"Ermöglicht der App den Zugriff auf Daten des Körpersensors, etwa solche zur Herzfrequenz, zur Temperatur und zum Blutsauerstoffanteil, während die App in Benutzung ist."</string>
+    <string name="permdesc_bodySensors" product="default" msgid="7652650410295512140">"Ermöglicht der App den Zugriff auf Daten des Körpersensors, etwa solche zur Herzfrequenz, zur Temperatur und zur Sauerstoffsättigung, während die App in Benutzung ist."</string>
     <string name="permlab_bodySensors_background" msgid="4912560779957760446">"Zugriff auf Daten des Körpersensors, etwa Herzfrequenz, wenn im Hintergrund"</string>
-    <string name="permdesc_bodySensors_background" product="default" msgid="8870726027557749417">"Ermöglicht der App den Zugriff auf Daten des Körpersensors, etwa solche zur Herzfrequenz, zur Temperatur und zum Blutsauerstoffanteil, während die App im Hintergrund ist."</string>
+    <string name="permdesc_bodySensors_background" product="default" msgid="8870726027557749417">"Ermöglicht der App den Zugriff auf Daten des Körpersensors, etwa solche zur Herzfrequenz, zur Temperatur und zur Sauerstoffsättigung, während die App im Hintergrund ist."</string>
     <string name="permlab_readCalendar" msgid="6408654259475396200">"Kalendertermine und Details lesen"</string>
     <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"Diese App kann alle auf deinem Tablet gespeicherten Kalendertermine lesen und deine Kalenderdaten teilen oder speichern."</string>
     <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Diese App kann alle auf deinem Android TV-Gerät gespeicherten Kalendertermine lesen und die Kalenderdaten teilen oder speichern."</string>
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Geschäftliche Apps nicht mehr pausieren?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Nicht mehr pausieren"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Notruf"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Displaysperre einrichten"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Displaysperre einrichten"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Richte zur Nutzung des privaten Bereichs auf dem Gerät die Displaysperre ein"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"App ist nicht verfügbar"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ist derzeit nicht verfügbar."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nicht verfügbar"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index c030d25..eafaf32 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Αναίρ. παύσης εφαρμ. εργασιών;"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Αναίρεση παύσης"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Έκτακτη ανάγκη"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ρυθμίστε ένα κλείδωμα οθόνης"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ρύθμιση κλειδώματος οθόνης"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ορίστε κλείδωμα οθόνης"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> δεν διατίθεται"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index cecdce6..7dd6a5c 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Unpause work apps?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Unpause"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergency"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Set a screen lock"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Set screen lock"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"To use your private space, set a screen lock on this device"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index c3cf404..58c015b 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Unpause work apps?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Unpause"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergency"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Set a screen lock"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Set screen lock"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"To use your private space, set a screen lock on this device"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index cda0168..fd0cdd5 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Unpause work apps?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Unpause"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergency"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Set a screen lock"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Set screen lock"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"To use your private space, set a screen lock on this device"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index f979e27..3dfadb2 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Unpause work apps?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Unpause"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergency"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Set a screen lock"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Set screen lock"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"To use your private space, set a screen lock on this device"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index e620c35..6c6f1c9 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‏‏‎‏‏‏‎‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‎‏‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‎‏‎‏‏‏‎‏‎‏‎‏‎Unpause work apps?‎‏‎‎‏‎"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‎‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‎‎‏‏‎‎‎‎Unpause‎‏‎‎‏‎"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‎‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‏‏‏‎‎‏‏‎‏‏‎‏‎‎‎‏‎‎‎‏‎‎Emergency‎‏‎‎‏‎"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‏‎‏‎‏‏‏‎‎Set a screen lock‎‏‎‎‏‎"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‏‎‎‎‏‏‎‎‏‎‏‏‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‎‎‏‎‏‏‏‎Set screen lock‎‏‎‎‏‎"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‏‏‎‏‏‏‏‎‏‎‎‏‏‎‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‎‏‏‎‏‏‎‎‏‏‏‎‏‏‎‎To use your private space, set a screen lock on this device‎‏‎‎‏‎"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‏‏‎‎‎‎‎‎‏‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‎App is not available‎‏‎‎‏‎"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‎‎‏‏‎‎‏‎‏‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is not available right now.‎‏‎‎‏‎"</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‏‏‎‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‎‎‎‏‏‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="ACTIVITY">%1$s</xliff:g>‎‏‎‎‏‏‏‎ unavailable‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index da500d7..d7af663 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -109,7 +109,7 @@
     <string name="serviceClassPAD" msgid="6850244583416306321">"PAD"</string>
     <string name="roamingText0" msgid="7793257871609854208">"Indicador de roaming activado"</string>
     <string name="roamingText1" msgid="5073028598334616445">"Indicador de roaming desactivado"</string>
-    <string name="roamingText2" msgid="2834048284153110598">"Indicador de roaming titilando"</string>
+    <string name="roamingText2" msgid="2834048284153110598">"Indicador de roaming parpadeando"</string>
     <string name="roamingText3" msgid="831690234035748988">"Fuera del vecindario"</string>
     <string name="roamingText4" msgid="2171252529065590728">"Fuera de construcción"</string>
     <string name="roamingText5" msgid="4294671587635796641">"Roaming: sistema preferido"</string>
@@ -1987,6 +1987,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"¿Reanudar apps de trabajo?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Reanudar"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergencia"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Configura bloqueo de pantalla"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Conf. un bloqueo de pantalla"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para usar esp. privado, configura un bloqueo de pantalla"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"La app no está disponible"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible en este momento."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no disponible"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 35cd1eb..02e29c0 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1987,6 +1987,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"¿Reactivar apps de trabajo?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Reactivar"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergencia"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Define un bloqueo de pantalla"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Establecer bloqueo de pantalla"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para usar el espacio privado, define un bloqueo de pantalla"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"La aplicación no está disponible"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"En estos momentos, <xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no disponible"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 24ee884..2fe8731 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Kas lõpetada töörakenduste peatamine?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Lõpeta peatamine"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Hädaolukord"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Seadistage ekraanilukk"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Seadistage ekraanilukk"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Seadistage oma privaatse ruumi jaoks seadmele ekraanilukk"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Rakendus ei ole saadaval"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei ole praegu saadaval."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ei ole saadaval"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 583f8a9..c28191a 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Laneko aplikazioak berraktibatu?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Berraktibatu"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Larrialdia"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ezarri pantailaren blokeoa"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ezarri pantailaren blokeoa"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Eremu pribatua erabiltzeko, ezarri pantailaren blokeoa gailuan"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Aplikazioa ez dago erabilgarri"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ez dago erabilgarri une honetan."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ez dago erabilgarri"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 52de6da..7155bf4 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -633,8 +633,8 @@
     <string name="permdesc_imagesWrite" msgid="5195054463269193317">"به برنامه اجازه می‌دهد مجموعه عکستان را تغییر دهد."</string>
     <string name="permlab_mediaLocation" msgid="7368098373378598066">"خواندن مکان‌ها از مجموعه رسانه شما"</string>
     <string name="permdesc_mediaLocation" msgid="597912899423578138">"به برنامه اجازه می‌دهد مکان‌ها را از مجموعه رسانه‌تان بخواند."</string>
-    <string name="biometric_app_setting_name" msgid="3339209978734534457">"استفاده از زیست‌سنجشی"</string>
-    <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"استفاده از زیست‌سنجشی یا قفل صفحه"</string>
+    <string name="biometric_app_setting_name" msgid="3339209978734534457">"استفاده از داده‌های زیست‌سنجشی"</string>
+    <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"استفاده از داده‌های زیست‌سنجشی یا قفل صفحه"</string>
     <string name="biometric_dialog_default_title" msgid="55026799173208210">"تأیید کنید این شمایید"</string>
     <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"برای ادامه، از زیست‌سنجشی استفاده کنید"</string>
     <string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"برای ادامه، از زیست‌سنجشی یا قفل صفحه استفاده کنید"</string>
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"مکث برنامه‌های کاری لغو شود؟"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"لغو مکث"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"اضطراری"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"قفل صفحه تنظیم کنید"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"تنظیم قفل صفحه"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"برای استفاده از فضای خصوصی، قفل صفحه تنظیم کنید"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> دردسترس نیست"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 20d4c14..11d5604 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Laita työsovellukset päälle?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Laita päälle"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Hätätilanne"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Näytön lukituksen asettaminen"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Aseta näytön lukitus"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Edellyttää näytön lukitusta"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Sovellus ei ole käytettävissä"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei ole nyt käytettävissä."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ei käytettävissä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index b634942..bec2f1f 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1987,6 +1987,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Réactiver les applis pros?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Réactiver"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Urgence"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Config. Verrouillage d\'écran"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Config. Verrouillage d\'écran"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Config. VÉ pour util. Esp. pr."</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"L\'application n\'est pas accessible"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas accessible pour le moment."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non accessible"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index f0ed3d6..d76b1ef 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1987,6 +1987,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Réactiver les applis pro ?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Réactiver"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Urgence"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Définir verrouillage écran"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Activer verrouillage écran"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Pour utiliser votre espace privé, définissez un verrouillage de l\'écran sur cet appareil"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Application non disponible"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas disponible pour le moment."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponible"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index da791af..6b7507a 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Reactivar apps do traballo?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Reactivar"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emerxencia"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Define un bloqueo de pantalla"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Define un bloqueo de pantalla"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para usar o espazo privado, define un bloqueo de pantalla"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"A aplicación non está dispoñible"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"A aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> non está dispoñible neste momento."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non está dispoñible"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 8f6affa..9f4919d 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"ઑફિસની થોભાવેલી ઍપ ચાલુ કરીએ?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"ફરી ચાલુ કરો"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ઇમર્જન્સી"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"સ્ક્રીન લૉક સેટ કરો"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"સ્ક્રીન લૉક સેટ કરો"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"તમારી ખાનગી સ્પેસનો ઉપયોગ કરવા, આ ડિવાઇસ પર સ્ક્રીન લૉક સેટ કરો"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ઉપલબ્ધ નથી"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 53b39ff..6e91d3a 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"वर्क ऐप्लिकेशन चालू करने हैं?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"चालू करें"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"आपातकालीन कॉल"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"स्क्रीन लॉक सेट करें"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"स्क्रीन लॉक सेट करें"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"प्राइवेट स्पेस के लिए, इस डिवाइस पर स्क्रीन लॉक सेट करें"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध नहीं है"</string>
@@ -2359,9 +2362,9 @@
     <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"इससे साथी ऐप्लिकेशन को बैकग्राउंड में फ़ोरग्राउंड सेवाएं चलाने की अनुमति मिलती है."</string>
     <string name="mic_access_on_toast" msgid="2666925317663845156">"माइक्रोफ़ोन इस्तेमाल किया जा सकता है"</string>
     <string name="mic_access_off_toast" msgid="8111040892954242437">"माइक्रोफ़ोन को ब्लॉक किया गया है"</string>
-    <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"कॉन्टेंट डिसप्ले नहीं किया जा सकता"</string>
+    <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"स्क्रीन शेयर नहीं की जा सकती"</string>
     <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"कोई दूसरा केबल इस्तेमाल करके फिर से कोशिश करें"</string>
-    <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"आपका डिवाइस बहुत गर्म हो गया है. जब तक यह ठंडा नहीं हो जाता, तब तक दूसरे डिवाइस पर इसकी स्क्रीन डिसप्ले नहीं की जा सकती"</string>
+    <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"आपका डिवाइस बहुत गर्म हो गया है. जब तक यह ठंडा नहीं हो जाता, तब तक दूसरे डिवाइस पर इसकी स्क्रीन शेयर नहीं की जा सकती"</string>
     <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual screen"</string>
     <string name="concurrent_display_notification_active_title" msgid="4892473462327943673">"Dual screen की सुविधा चालू है"</string>
     <string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g>, कॉन्टेंट दिखाने के लिए दोनों स्क्रीन का इस्तेमाल कर रहा है"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 9af2496..4682f84 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1987,6 +1987,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Pokrenuti poslovne aplikacije?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Ponovno pokreni"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Hitni slučaj"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Postavite zaključavanje zaslona"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Postavi zaključavanje zaslona"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Za upotrebu privatnog prostora postavite zaključavanje zaslona na ovom uređaju"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutačno nije dostupna."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – nije dostupno"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 17f80d1..bde17d0 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Feloldja a munkahelyi appokat?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Szüneteltetés feloldása"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Vészhelyzet"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Állítson be képernyőzárat"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Képernyőzár beállítása"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"A magánterület használatához állítson be képernyőzárat"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Az alkalmazás nem hozzáférhető"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> jelenleg nem hozzáférhető."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"A(z) <xliff:g id="ACTIVITY">%1$s</xliff:g> nem áll rendelkezése"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 51d0ded..8caacd3 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Վերսկսե՞լ աշխ. հավելվածները"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Վերսկսել"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Արտակարգ իրավիճակ"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Կարգավորեք էկրանի կողպումը"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Կարգավորել էկրանի կողպումը"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Մասնավոր տարածքն օգտագործելու համար այս սարքում կարգավորեք էկրանի կողպումը"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>՝ անհասանելի է"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 29dc273..2020a75 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Batalkan jeda aplikasi kerja?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Batalkan jeda"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Darurat"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Setel kunci layar"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Setel kunci layar"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Untuk menggunakan ruang pribadi, setel kunci layar di perangkat ini"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Aplikasi tidak tersedia"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak tersedia saat ini."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> tidak tersedia"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index ca702fa..f25a4b4 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Ljúka hléi vinnuforrita?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Ljúka hléi"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Neyðartilvik"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Stilltu skjálás"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Stilltu skjálás"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Stilltu skjálás í tækinu til að nota leynirými"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Forrit er ekki tiltækt"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ekki tiltækt núna."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ekki í boði"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 2cb3d3d..06fa36f 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1987,6 +1987,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Riattivare le app di lavoro?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Riattiva"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergenza"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Imposta un blocco schermo"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Imposta il blocco schermo"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Per utilizzare il tuo spazio privato, imposta un blocco schermo sul dispositivo"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"L\'app non è disponibile"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> non è al momento disponibile."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non disponibile"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 3e7c79e..1a609b9 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1987,6 +1987,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"להפעיל את האפליקציות לעבודה?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"ביטול ההשהיה"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"שיחת חירום"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"הגדרת נעילת מסך"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"הגדרה של נעילת מסך"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"כדי להשתמש במרחב הפרטי יש להגדיר נעילת מסך במכשיר"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> לא זמינה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 576a495..688450e 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"仕事用アプリの停止解除"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"停止解除"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"緊急通報"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"画面ロックの設定"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"画面ロックを設定"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"プライベート スペースには画面ロックの設定が必要です"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>は利用できません"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 571ae42..a1e489a 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"კვლავ გააქტიურდეს სამსახურის აპები?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"გააქტიურება"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"საგანგებო სიტუაცია"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"ეკრანის დაბლოკვის დაყენება"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ეკრანის დაბლოკვის დაყენება"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"კერძო სივრცის გამოსაყენებლად დააყენეთ ამ მოწყობილობაზე ეკრანის დაბლოკვა"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> მიუწვდომელია"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 4f50140..0bef068 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Жұмыс қолданбаларын қайта қосасыз ба?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Қайта қосу"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Құтқару қызметіне қоңырау шалу"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Экран құлпын орнатыңыз"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Экран құлпын орнату"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Құпия кеңістігіңізді қолдану үшін осы құрылғыда экран құлпын орнатыңыз."</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> қолжетімсіз"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 8c33299..1f805bf 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"ឈប់ផ្អាកកម្មវិធីការងារឬ?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"ឈប់ផ្អាក"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ពេលមានអាសន្ន"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"កំណត់​ការចាក់​សោអេក្រង់"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"កំណត់​ការចាក់​សោ​អេក្រង់"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ដើម្បីប្រើលំហឯកជនរបស់អ្នក សូមកំណត់ការចាក់សោអេក្រង់នៅលើឧបករណ៍នេះ"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"មិនអាចប្រើ <xliff:g id="ACTIVITY">%1$s</xliff:g> បានទេ"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index e106f16..c3fab52 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"ಕೆಲಸದ ಆ್ಯಪ್ ವಿರಾಮ ರದ್ದುಮಾಡಬೇಕೇ"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"ವಿರಾಮವನ್ನು ರದ್ದುಗೊಳಿಸಿ"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ತುರ್ತು"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಸೆಟ್ ಮಾಡಿ"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಸೆಟ್ ಮಾಡಿ"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ನಿಮ್ಮ ಪ್ರೈವೆಟ್ ಸ್ಪೇಸ್ ಅನ್ನು ಬಳಸಲು, ಈ ಸಾಧನದಲ್ಲಿ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಸೆಟ್ ಮಾಡಿ"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ಲಭ್ಯವಿಲ್ಲ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index ff480c5..9b7556a 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"직장 앱 일시중지를 해제하시겠습니까?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"일시중지 해제"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"긴급 전화"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"화면 잠금 설정"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"화면 잠금 설정"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"비공개 스페이스를 사용하려면 이 기기에 화면 잠금을 설정하세요"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 사용할 수 없음"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index e44689d..71c128d 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Жумуш колдонмолорун иштетесизби?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Иштетүү"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Шашылыш чалуу"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Экран кулпусун коюп алыңыз"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Экран кулпусун коюу"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Жеке мейкиндикти колдонуу үчүн бул түзмөктүн экранын кулпулаңыз"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> жеткиликсиз"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 1f6c1a1..8c19e7b 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"ຍົກເລີກການຢຸດຊົ່ວຄາວແອັບບ່ອນເຮັດວຽກບໍ?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"ຍົກເລີກການຢຸດຊົ່ວຄາວ"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ສຸກເສີນ"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"ຕັ້ງການລັອກໜ້າຈໍ"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ຕັ້ງການລັອກໜ້າຈໍ"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ເພື່ອໃຊ້ພື້ນທີ່ສ່ວນບຸກຄົນ, ໃຫ້ຕັ້ງລັອກໜ້າຈໍຢູ່ອຸປະກອນນີ້"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"ບໍ່ສາມາດໃຊ້ <xliff:g id="ACTIVITY">%1$s</xliff:g> ໄດ້"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 0196351..bf227d0 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1988,6 +1988,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Atš. darbo progr. pristabd.?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Atšaukti pristabdymą"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Pagalbos tarnyba"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ekrano užrako nustatymas"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Nustatykite ekrano užraktą"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Jei norite naudoti privačią erdvę, nustatykite ekrano užraktą šiame įrenginyje"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Programa nepasiekiama."</string>
     <string name="app_blocked_message" msgid="542972921087873023">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ šiuo metu nepasiekiama."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"„<xliff:g id="ACTIVITY">%1$s</xliff:g>“ nepasiekiama"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 46aae3f..a575e2a 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1987,6 +1987,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Vai aktivizēt darba lietotnes?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Aktivizēt"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Ārkārtas zvans"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Iestatiet ekrāna bloķēšanu"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Iestatīt ekrāna bloķēšanu"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Lai izmantotu privāto telpu, iestatiet ekrāna bloķēšanu."</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Lietotne nav pieejama"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> pašlaik nav pieejama."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nav pieejams"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 1c85e47..0ff49ed 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Да се актив. работните аплик.?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Прекини ја паузата"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Итен случај"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Поставете заклучување екран"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Поставување заклучување екран"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"За да користите „Приватен простор“, поставете заклучување екран на уредов"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> е недостапна"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 9917448..2648a38 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"വർക്ക് ആപ്പുകൾ പുനരാരംഭിക്കണോ?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"പുനരാരംഭിക്കുക"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"അടിയന്തരം"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"സ്‌ക്രീൻ ലോക്ക് സജ്ജീകരിക്കൂ"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"സ്‌ക്രീൻ ലോക്ക് സജ്ജീകരിക്കൂ"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"സ്വകാര്യ സ്പേസിന്, ഇതിൽ സ്ക്രീൻ ലോക്ക് സജ്ജീകരിക്കൂ"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ലഭ്യമല്ല"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 48d926c..c7f8524 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Ажлын аппыг үргэлжлүүлэх үү?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Үргэлжлүүлэх"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Яаралтай тусламж"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Дэлгэцийн түгжээ тохируулах"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Дэлгэцийн түгжээ тохируулах"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Хаалттай орон зайгаа ашиглах бол уг төхөөрөмжид дэлгэцийн түгжээ тохируулна уу"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> боломжгүй байна"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 8fb6b0f..0c625c7 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"वर्क ॲप्स पुन्हा सुरू करायची?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"पुन्हा सुरू करा"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"आणीबाणी"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"स्क्रीन लॉक सेट करा"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"स्क्रीन लॉक सेट करा"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"तुमची खाजगी स्पेस वापरण्यास, या डिव्हाइसवर स्क्रीन लॉक सेट करा"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध नाही"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 7112ed3..9c81b79 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Nyahjeda apl kerja?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Nyahjeda"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Kecemasan"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Tetapkan kunci skrin"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Tetapkan kunci skrin"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Tetapkan kunci skrin pada peranti untuk guna ruang privasi"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Apl tidak tersedia"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak tersedia sekarang."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> tidak tersedia"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 2c3e7b74..2d603bc 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"အလုပ်သုံးအက်ပ် ပြန်ဖွင့်မလား။"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"ပြန်ဖွင့်ရန်"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"အရေးပေါ်"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"ဖန်သားပြင်လော့ခ် သတ်မှတ်ပါ"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ဖန်သားပြင်လော့ခ် သတ်မှတ်ရန်"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"သင့်သီးသန့်နေရာသုံးရန် ဤစက်၌ ဖန်သားပြင်လော့ခ် သတ်မှတ်ပါ"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> မရနိုင်ပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 541e1b5..2ea9d40 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Vil du slå på jobbapper igjen?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Slå på"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Nød"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Angi en skjermlås"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Angi skjermlås"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"For å bruke det private området, angi en skjermlås på enheten"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Appen er ikke tilgjengelig"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ikke tilgjengelig for øyeblikket."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> er utilgjengelig"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 8c951e0..b7996f7 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"कामसम्बन्धी एपहरू अनपज गर्ने हो?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"अनपज गर्नुहोस्"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"आपत्‌कालीन"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"स्क्रिन लक सेटअप गर्नुहोस्"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"स्क्रिन लक सेटअप गर्नुहोस्"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"निजी स्पेस प्रयोग गर्न यो डिभाइसमा स्क्रिन लक सेटअप गर्नुहोस्"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध छैन"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index bbcc2aa..8b60b53 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Werk-apps hervatten?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Hervatten"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Noodgeval"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Schermvergrendeling instellen"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Schermvergrendeling instellen"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Als je je privéruimte wilt gebruiken, stel je een schermvergrendeling op dit apparaat in"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"App is niet beschikbaar"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is momenteel niet beschikbaar."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> niet beschikbaar"</string>
@@ -2359,7 +2362,7 @@
     <string name="permdesc_startForegroundServicesFromBackground" msgid="4071826571656001537">"Hiermee kan een bijbehorende app services op de voorgrond vanuit de achtergrond starten."</string>
     <string name="mic_access_on_toast" msgid="2666925317663845156">"Microfoon is beschikbaar"</string>
     <string name="mic_access_off_toast" msgid="8111040892954242437">"Microfoon is geblokkeerd"</string>
-    <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Kan niet spiegelen naar scherm"</string>
+    <string name="connected_display_unavailable_notification_title" msgid="5265409360902073556">"Kan niet mirroren naar scherm"</string>
     <string name="connected_display_unavailable_notification_content" msgid="3845903313751217516">"Gebruik een andere kabel en probeer het opnieuw"</string>
     <string name="connected_display_thermally_unavailable_notification_content" msgid="9205758199439955949">"Je apparaat is te warm en kan pas naar het scherm mirroren als het is afgekoeld"</string>
     <string name="concurrent_display_notification_name" msgid="1526911253558311131">"Dual Screen"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index d8bcbd1..b3e62aa 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"ୱାର୍କ ଆପ୍ସକୁ ପୁଣି ଚାଲୁ କରିବେ?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ଜରୁରୀକାଳୀନ"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"ଏକ ସ୍କ୍ରିନ୍ ଲକ୍ ସେଟ୍ କରନ୍ତୁ"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ସ୍କ୍ରିନ ଲକ ସେଟ କରନ୍ତୁ"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ଆପଣଙ୍କ ପ୍ରାଇଭେଟ ସ୍ପେସ ବ୍ୟବହାର କରିବାକୁ ଏହି ଡିଭାଇସରେ ଏକ ସ୍କ୍ରିନ ଲକ ସେଟ କରନ୍ତୁ"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ଉପଲବ୍ଧ ନାହିଁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index b762d66..283813d 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਤੋਂ ਰੋਕ ਹਟਾਈਏ?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"ਰੋਕ ਹਟਾਓ"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ਐਮਰਜੈਂਸੀ"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"ਸਕ੍ਰੀਨ ਲਾਕ ਸੈੱਟ ਕਰੋ"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ਸਕ੍ਰੀਨ ਲਾਕ ਸੈੱਟ ਕਰੋ"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ਆਪਣੀ ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ ਵਰਤਣ ਲਈ, ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸਕ੍ਰੀਨ ਲਾਕ ਸੈੱਟ ਕਰੋ"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 5f3e683..5e0e670 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1988,6 +1988,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Cofnąć wstrzymanie aplikacji służbowych?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Cofnij wstrzymanie"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Połączenie alarmowe"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ustaw blokadę ekranu"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ustaw blokadę ekranu"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Aby korzystać z przestrzeni prywatnej, ustaw na tym urządzeniu blokadę ekranu"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Aplikacja jest niedostępna"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest obecnie niedostępna."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – brak dostępu"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 9887bf6..3ccb86a 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1987,6 +1987,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Reativar apps de trabalho?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Reativar"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergência"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Defina um bloqueio de tela"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Definir bloqueio de tela"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para usar o espaço privado, defina um bloqueio de tela neste dispositivo"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 9903acb..f26eb78 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1987,6 +1987,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Retomar apps de trabalho?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Retomar"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergência"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Defina um bloqueio de ecrã"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Definir bloqueio de ecrã"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para usar espaço privado, defina bloqueio de ecrã no disp."</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"A app não está disponível"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"De momento, a app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 9887bf6..3ccb86a 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1987,6 +1987,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Reativar apps de trabalho?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Reativar"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergência"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Defina um bloqueio de tela"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Definir bloqueio de tela"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para usar o espaço privado, defina um bloqueio de tela neste dispositivo"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 73d92fb..049ef0c 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1987,6 +1987,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Reactivezi aplicații de lucru?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Reactivează"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Urgență"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Setează o blocare a ecranului"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Setează blocarea ecranului"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ca să folosești spațiul privat, setează blocarea ecranului pe acest dispozitiv"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Aplicația nu este disponibilă"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu este disponibilă momentan."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nu este disponibilă"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 5b434a5..8abfb65 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1988,6 +1988,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Включить рабочие приложения?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Включить"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Экстренный вызов"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Настройте блокировку экрана"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Настроить блокировку экрана"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Чтобы использовать личное пространство, настройте блокировку экрана на этом устройстве."</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недоступно: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 5a27118..5078ee0 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"කාර්ය යෙදුම් විරාම නොකරන්න ද?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"විරාම නොකරන්න"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"හදිසි අවස්ථාව"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"තිර අගුලක් සකසන්න"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"තිර අගුල සකසන්න"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ඔබේ රහසිගත අවකාශය භාවිතා කිරීමට, මෙම උපාංගයේ තිර අගුලක් සකසන්න"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> නොතිබේ"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 16a56d3..a10cc48 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1988,6 +1988,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Zrušiť pozast. prac. aplikácií?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Zrušiť pozastavenie"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Tiesňová linka"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Nastavte zámku obrazovky"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Nastavte zámku obrazovky"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ak chcete používať súkromný priestor, nastavte v tomto zariadení zámku obrazovky"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Aplikácia nie je dostupná"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> nie je teraz dostupná."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nie je k dispozícii"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 79a275c..70eb803 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1988,6 +1988,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Želite znova aktivirati delovne aplikacije?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Znova aktiviraj"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Nujni primer"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Nastavitev zaklepanja zaslona"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Nastavite zaklepanje zaslona"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Če želite uporabljati zasebni prostor, v tej napravi nastavite zaklepanje zaslona"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija ni na voljo"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno ni na voljo."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"»<xliff:g id="ACTIVITY">%1$s</xliff:g>« ni na voljo"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index fc2e715..61d815d 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Hiq nga pauza apl. e punës?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Hiq nga pauza"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Urgjenca"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Cakto një kyçje ekrani"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Cakto kyçjen e ekranit"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Për të përdorur hapësirën private, cakto një kyçje ekrani në këtë pajisje"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Aplikacioni nuk ofrohet"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk ofrohet për momentin."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nuk ofrohet"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 4f9ce47..f0c8a20 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1987,6 +1987,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Укључити пословне апликације?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Поново активирај"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Хитан случај"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Подесите закључавање екрана"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Подеси закључавање екрана"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Да бисте користили приватни простор, подесите закључавање екрана на овом уређају"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – није доступно"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 7f0a201..79cdce4 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1489,7 +1489,7 @@
     <string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"Tillåter att en app begär paketborttagning."</string>
     <string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"får be om tillstånd att ignorera batterioptimering"</string>
     <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Appen får be om tillstånd att ignorera batterioptimering."</string>
-    <string name="permlab_queryAllPackages" msgid="2928450604653281650">"fråga alla paket"</string>
+    <string name="permlab_queryAllPackages" msgid="2928450604653281650">"sök efter alla paket"</string>
     <string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Tillåter att en app ser alla installerade paket."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Peka två gånger för zoomkontroll"</string>
     <string name="gadget_host_error_inflating" msgid="2449961590495198720">"Det gick inte att lägga till widgeten."</string>
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Vill du återuppta jobbappar?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Återuppta"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Nödsituation"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ställ in ett skärmlås"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ställ in skärmlås"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ställ in ett skärmlås för enheten om du vill använda ditt privata område."</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Appen är inte tillgänglig"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> är inte tillgängligt just nu."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> är inte tillgänglig"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 4d00440..4111f3a 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Je, ungependa kuacha kusitisha programu za kazini?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Acha kusitisha"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Simu za dharura"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Weka mbinu ya kufunga skrini"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Weka mbinu ya kufunga skrini"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ili utumie sehemu ya faragha, weka mbinu ya kufunga skrini kwenye kifaa hiki"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Programu haipatikani"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> haipatikani hivi sasa."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> haipatikani"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index f962728..3d33923 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"பணி ஆப்ஸை மீண்டும் இயக்கவா?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"மீண்டும் இயக்கு"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"அவசர அழைப்பு"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"திரைப் பூட்டை அமையுங்கள்"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"திரைப் பூட்டை அமை"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ரகசிய இடத்தைப் பயன்படுத்த, சாதனத்தில் திரைப் பூட்டை அமையுங்கள்"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> இல்லை"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 30c2812..5887cd3 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"వర్క్ యాప్స్ అన్‌పాజ్ చేయాలా?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"అన్‌పాజ్ చేయండి"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ఎమర్జెన్సీ"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"స్క్రీన్ లాక్‌ను సెట్ చేయండి"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"స్క్రీన్ లాక్‌ను సెట్ చేయండి"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"మీ ప్రైవేట్ స్పేస్‌ను ఉపయోగించడానికి, ఈ పరికరంలో స్క్రీన్ లాక్ సెట్ చేయండి"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> అందుబాటులో లేదు"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index c92d613..51ff5ae 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"ยกเลิกการหยุดแอปงานชั่วคราวไหม"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"ยกเลิกการหยุดชั่วคราว"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ฉุกเฉิน"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"ตั้งล็อกหน้าจอ"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ตั้งล็อกหน้าจอ"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"หากต้องการใช้พื้นที่ส่วนตัว ให้ตั้งการล็อกหน้าจอในอุปกรณ์นี้"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ไม่พร้อมใช้งาน"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index d944334..43ce6bc 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"I-unpause ang mga work app?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"I-unpause"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Emergency"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Magtakda ng lock ng screen"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Itakda ang lock ng screen"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para gamitin ang iyong pribadong space, magtakda ng lock ng screen sa device na ito."</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Hindi available ang app"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"Hindi available sa ngayon ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"Hindi available ang <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index dfae301..1df9b8d 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"İş uygulamaları devam ettirilsin mi?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Devam ettir"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Acil durum"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ekran kilidi ayarlayın"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ekran kilidi ayarla"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Özel alanı kullanmak için cihazda ekran kilidi ayarlayın"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Uygulama kullanılamıyor"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması şu anda kullanılamıyor."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> kullanılamıyor"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index c8fa210..903261c 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1988,6 +1988,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Увімкнути робочі додатки?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Увімкнути"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Екстрений виклик"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Налаштуйте блокування екрана"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Налаштувати блокування екрана"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Для доступу до приватного простору налаштуйте блокування екрана"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недоступно: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 5ad1f18..bed6cf8 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"ورک ایپس کو غیر موقوف کریں؟"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"غیر موقوف کریں"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"ایمرجنسی"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"اسکرین لاک سیٹ کریں"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"اسکرین لاک سیٹ کریں"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"اپنی نجی اسپیس استعمال کرنے کیلئے، اس آلہ پر اسکرین لاک سیٹ کریں"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> دستیاب نہیں ہے"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index a3ffb9c..1316898 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Ishga oid ilovalar qaytarilsinmi?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Davom ettirish"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Favqulodda holat"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ekran qulfini sozlash"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ekran qulfini sozlash"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Maxfiy makon ishlatish uchun bu qurilma ekran qulfini sozlang"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Ilova ishlamayapti"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"Ayni vaqtda <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi ishlamayapti."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> kanali ish faoliyatida emas"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 8f52be0..4587a62 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Tiếp tục dùng ứng dụng công việc?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Tiếp tục dùng"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Khẩn cấp"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Đặt phương thức khoá màn hình"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Đặt phương thức khoá màn hình"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Để dùng không gian riêng tư, hãy thiết lập một phương thức khoá màn hình trên thiết bị này"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Ứng dụng này không dùng được"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> hiện không dùng được."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"Không hỗ trợ <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 28f563d..c58c0de 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"是否为工作应用解除暂停状态?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"解除暂停"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"紧急呼叫"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"设置一种屏锁方式"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"设置屏锁方式"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"若要使用私密空间,请在此设备上设置屏锁方式"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>不可用"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 59a2abd..b72569a 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"要取消暫停工作應用程式嗎?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"取消暫停"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"撥打緊急電話"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"設定螢幕鎖定"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"設定螢幕鎖定"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"如要使用私人空間,請在此裝置上設定螢幕鎖定功能"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"無法使用「<xliff:g id="ACTIVITY">%1$s</xliff:g>」"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 2233668..3c7619c 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"要解除工作應用程式的暫停狀態嗎?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"取消暫停"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"撥打緊急電話"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"設定螢幕鎖定功能"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"設定螢幕鎖定功能"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"如要使用私人空間,請在這部裝置設定螢幕鎖定功能"</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>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"無法存取「<xliff:g id="ACTIVITY">%1$s</xliff:g>」"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 176c3743..c9dd914 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1986,6 +1986,9 @@
     <string name="work_mode_off_title" msgid="6367463960165135829">"Susa ukumisa ama-app omsebenzi?"</string>
     <string name="work_mode_turn_on" msgid="5316648862401307800">"Qhubekisa"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Isimo esiphuthumayo"</string>
+    <string name="set_up_screen_lock_title" msgid="8346083801616474030">"Setha ukukhiya isikrini"</string>
+    <string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Setha ukukhiya isikrini"</string>
+    <string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ukuze usebenzise isikhala esigodliwe, setha ukukhiya kwesikrini kule divayisi."</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Uhlelo lokusebenza alutholakali"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayitholakali khona manje."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"okungatholakali <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index c1fd619..48cf09a 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4409,7 +4409,7 @@
         <attr name="requireDeviceScreenOn" format="boolean"/>
         <!-- Whether the device should default to observe mode when this service is
              default or in the foreground. -->
-        <attr name="defaultToObserveMode" format="boolean"/>
+        <attr name="shouldDefaultToObserveMode" format="boolean"/>
     </declare-styleable>
 
     <!-- Use <code>offhost-apdu-service</code> as the root tag of the XML resource that
@@ -4436,7 +4436,7 @@
         <attr name="requireDeviceScreenOn"/>
         <!-- Whether the device should default to observe mode when this service is
              default or in the foreground. -->
-        <attr name="defaultToObserveMode"/>
+        <attr name="shouldDefaultToObserveMode"/>
     </declare-styleable>
 
     <!-- Specify one or more <code>aid-group</code> elements inside a
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index b2e0be7c..c882938 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1618,15 +1618,13 @@
         <!-- Data (photo, file, account) upload/download, backup/restore, import/export, fetch,
             transfer over network between device and cloud.
 
-            <p><b>THIS TYPE IS DEPRECATED.</b>
-            <p><em>Note: For apps with <code>targetSdkVersion</code>
-            {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} and above, this type should
-            <b>NOT</b> be used: calling
-            {@link android.app.Service#startForeground(int, android.app.Notification, int)}
-            with this type on devices running
-            {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} is still allowed, but it may
-            throw an {@link android.app.InvalidForegroundServiceTypeException} in future platform
-            releases.</em>
+            <p>For apps with <code>targetSdkVersion</code>
+            {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, this type should NOT
+            be used: calling
+            {@link android.app.Service#startForeground(int, android.app.Notification, int)} with
+            this type on devices running {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}
+            is still allowed, but calling it with this type on devices running future platform
+            releases may get a {@link android.app.InvalidForegroundServiceTypeException}.
         -->
         <flag name="dataSync" value="0x01" />
         <!-- Music, video, news or other media play.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1f06b0b..90f2731 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3348,26 +3348,23 @@
     <string name="config_carrierAppInstallDialogComponent" translatable="false"
             >com.android.simappdialog/com.android.simappdialog.InstallCarrierAppActivity</string>
 
-    <!-- Name of the default framework dialog that is used to get or save an app credential.
+    <!-- Name of the fallback CredentialManager dialog that is used to get or save an app
+     credential.
 
-    This UI should be always launch-able and is used as a fallback when an oem replacement activity
-    (defined at config_oemCredentialManagerDialogComponent) is undefined / not found. -->
-    <string name="config_credentialManagerDialogComponent" translatable="false"
+     If empty, no fallback will be used. IMPORTANT: In that case the OEM dialog value specified in
+     config_oemCredentialManagerDialogComponent must always launch-able. Otherwise, the
+     CredentialManager API contract is broken.
+
+     If specified, this UI should be always launch-able. It will be used as a fallback when the OEM
+     dialog value specified in config_oemCredentialManagerDialogComponent) is undefined / not
+     found. -->
+    <string name="config_fallbackCredentialManagerDialogComponent" translatable="false"
             >com.android.credentialmanager/com.android.credentialmanager.CredentialSelectorActivity</string>
-    <!-- Whether to allow the credential selector activity to be replaced by an activity at
-     run-time (restricted to the privileged activity specified by
-     config_credentialSelectorActivityName).
-
-     When disabled, the fallback activity defined at
-     config_credentialManagerDialogComponent will be used instead. -->
-    <bool name="config_enableOemCredentialManagerDialogComponent" translatable="false">true</bool>
     <!-- Fully qualified activity name providing the credential selector UI, that serves the
-     CredentialManager APIs.
+     CredentialManager APIs. Must be a system app component.
 
-     Used only when config_enableOemCredentialManagerDialogComponent is true.
-
-     If the activity specified cannot be found or launched, then the fallback activity defined at
-     config_credentialManagerDialogComponent will be used instead. -->
+     If empty, or if this activity specified cannot be found or launched, then the fallback activity
+     defined at config_fallbackCredentialManagerDialogComponent will be used instead. -->
     <string name="config_oemCredentialManagerDialogComponent" translatable="false"></string>
 
     <!-- Name of the broadcast receiver that is used to receive provider change events -->
@@ -3614,8 +3611,7 @@
     <!-- 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. -->
-    <!-- TODO(b/268563842) enable once activity snapshot is ready -->
-    <bool name="config_predictShowStartingSurface">false</bool>
+    <bool name="config_predictShowStartingSurface">true</bool>
 
     <!-- default window ShowCircularMask property -->
     <bool name="config_windowShowCircularMask">false</bool>
@@ -4101,6 +4097,13 @@
     <!-- How close vibration request should be when they're aggregated for dumpsys, in ms. -->
     <integer name="config_previousVibrationsDumpAggregationTimeMillisLimit">1000</integer>
 
+    <!-- How long history of vibration control service should be kept for the dumpsys. -->
+    <integer name="config_vibratorControlServiceDumpSizeLimit">50</integer>
+
+    <!-- How close requests to vibration control service should be when they're aggregated for
+         dumpsys, in ms. -->
+    <integer name="config_vibratorControlServiceDumpAggregationTimeMillisLimit">60000</integer>
+
     <!-- The default vibration strength, must be between 1 and 255 inclusive. -->
     <integer name="config_defaultVibrationAmplitude">255</integer>
 
@@ -6967,4 +6970,16 @@
 
     <!-- Whether to use file hashes cache in watchlist-->
     <bool name="config_watchlistUseFileHashesCache">false</bool>
+
+    <!-- Name of the package responsible to handle Contextual Search. -->
+    <string name="config_defaultContextualSearchPackageName" translatable="false" />
+
+    <!-- The key containing the entrypoint for Contextual Search. -->
+    <string name="config_defaultContextualSearchKey" translatable="false" />
+
+    <!-- The key containing the branching boolean for Contextual Search. -->
+    <string name="config_defaultContextualSearchEnabled" translatable="false" />
+
+    <!-- The key containing the branching boolean for legacy Search. -->
+    <string name="config_defaultContextualSearchLegacyEnabled" translatable="false" />
 </resources>
diff --git a/core/res/res/values/config_battery_saver.xml b/core/res/res/values/config_battery_saver.xml
index e1b0ef4..551cd0a 100644
--- a/core/res/res/values/config_battery_saver.xml
+++ b/core/res/res/values/config_battery_saver.xml
@@ -33,6 +33,9 @@
     <!-- Whether or not battery saver should be "sticky" when manually enabled. -->
     <bool name="config_batterySaverStickyBehaviourDisabled">false</bool>
 
+    <!-- Whether to enable "Battery Saver turned off" notification. -->
+    <bool name="config_batterySaverTurnedOffNotificationEnabled">true</bool>
+
     <!-- Config flag to track default disable threshold for Dynamic power savings enabled battery saver. -->
     <integer name="config_dynamicPowerSavingsDefaultDisableThreshold">80</integer>
 
diff --git a/core/res/res/values/config_display.xml b/core/res/res/values/config_display.xml
new file mode 100644
index 0000000..2e66060
--- /dev/null
+++ b/core/res/res/values/config_display.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright (C) 2024 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Resources used in DisplayManager.
+
+     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". -->
+
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether even dimmer feature is enabled. -->
+    <bool name="config_evenDimmerEnabled">false</bool>
+
+</resources>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 104b7cd..6e56fe2 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -73,13 +73,18 @@
     <bool name="auto_data_switch_ping_test_before_switch">true</bool>
     <java-symbol type="bool" name="auto_data_switch_ping_test_before_switch" />
 
+    <!-- TODO: remove after V -->
+    <!-- Boolean indicating whether allow to use a roaming nonDDS if user enabled its roaming. -->
+    <bool name="auto_data_switch_allow_roaming">true</bool>
+    <java-symbol type="bool" name="auto_data_switch_allow_roaming" />
+
     <!-- Define the tolerated gap of score for auto data switch decision, larger than which the
          device will switch to the SIM with higher score. The score is used in conjunction with the
          score table defined in
          CarrierConfigManager#KEY_AUTO_DATA_SWITCH_RAT_SIGNAL_SCORE_STRING_ARRAY.
          If 0, the device always switch to the higher score SIM.
          If < 0, the network type and signal strength based auto switch is disabled. -->
-    <integer name="auto_data_switch_score_tolerance">4000</integer>
+    <integer name="auto_data_switch_score_tolerance">-1</integer>
     <java-symbol type="integer" name="auto_data_switch_score_tolerance" />
 
     <!-- Boolean indicating whether the Iwlan data service supports persistence of iwlan ipsec
@@ -329,4 +334,9 @@
     <bool name="config_enable_cellular_on_boot_default">true</bool>
     <java-symbol type="bool" name="config_enable_cellular_on_boot_default" />
 
+    <!-- Defines metrics pull cooldown period. The default cooldown period is 23 hours,
+         some Telephony metrics need to be pulled more frequently  -->
+    <integer name="config_metrics_pull_cooldown_millis">82800000</integer>
+    <java-symbol type="integer" name="config_metrics_pull_cooldown_millis" />
+
 </resources>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index 5987f6e..3303c07 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -160,7 +160,7 @@
     <!-- @FlaggedApi("android.view.inputmethod.connectionless_handwriting") -->
     <public name="supportsConnectionlessStylusHandwriting" />
     <!-- @FlaggedApi("android.nfc.Flags.FLAG_OBSERVE_MODE") -->
-    <public name="defaultToObserveMode"/>
+    <public name="shouldDefaultToObserveMode"/>
     <!-- @FlaggedApi("android.security.asm_restrictions_enabled") -->
     <public name="allowCrossUidActivitySwitchFromBelow"/>
     <!-- @FlaggedApi("com.android.text.flags.use_bounds_for_width") -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index adf8d9f..5945f81 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1468,7 +1468,7 @@
         <item name="pointerIconHand">@drawable/pointer_hand_vector_icon</item>
         <item name="pointerIconContextMenu">@drawable/pointer_context_menu_vector_icon</item>
         <item name="pointerIconHelp">@drawable/pointer_help_vector_icon</item>
-        <item name="pointerIconWait">@drawable/pointer_wait_icon</item>
+        <item name="pointerIconWait">@drawable/pointer_wait_vector_icon</item>
         <item name="pointerIconCell">@drawable/pointer_cell_vector_icon</item>
         <item name="pointerIconCrosshair">@drawable/pointer_crosshair_vector_icon</item>
         <item name="pointerIconText">@drawable/pointer_text_vector_icon</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3284791..a025c8d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2083,6 +2083,8 @@
   <java-symbol type="integer" name="config_recentVibrationsDumpSizeLimit" />
   <java-symbol type="integer" name="config_previousVibrationsDumpSizeLimit" />
   <java-symbol type="integer" name="config_previousVibrationsDumpAggregationTimeMillisLimit" />
+  <java-symbol type="integer" name="config_vibratorControlServiceDumpSizeLimit" />
+  <java-symbol type="integer" name="config_vibratorControlServiceDumpAggregationTimeMillisLimit" />
   <java-symbol type="integer" name="config_defaultVibrationAmplitude" />
   <java-symbol type="dimen" name="config_hapticChannelMaxVibrationAmplitude" />
   <java-symbol type="dimen" name="config_keyboardHapticFeedbackFixedAmplitude" />
@@ -2295,8 +2297,7 @@
   <java-symbol type="string" name="config_customVpnAlwaysOnDisconnectedDialogComponent" />
   <java-symbol type="string" name="config_platformVpnConfirmDialogComponent" />
   <java-symbol type="string" name="config_carrierAppInstallDialogComponent" />
-  <java-symbol type="string" name="config_credentialManagerDialogComponent" />
-  <java-symbol type="bool" name="config_enableOemCredentialManagerDialogComponent" />
+  <java-symbol type="string" name="config_fallbackCredentialManagerDialogComponent" />
   <java-symbol type="string" name="config_oemCredentialManagerDialogComponent" />
   <java-symbol type="string" name="config_credentialManagerReceiverComponent" />
   <java-symbol type="string" name="config_defaultNetworkScorerPackageName" />
@@ -4123,6 +4124,7 @@
   <java-symbol type="bool" name="config_batterySaverSupported" />
   <java-symbol type="string" name="config_batterySaverDeviceSpecificConfig" />
   <java-symbol type="bool" name="config_batterySaverStickyBehaviourDisabled" />
+  <java-symbol type="bool" name="config_batterySaverTurnedOffNotificationEnabled" />
   <java-symbol type="integer" name="config_dynamicPowerSavingsDefaultDisableThreshold" />
   <java-symbol type="string" name="config_batterySaverScheduleProvider" />
   <java-symbol type="string" name="config_powerSaveModeChangedListenerPackage" />
@@ -4363,6 +4365,7 @@
   <java-symbol type="dimen" name="seekbar_thumb_exclusion_max_size" />
   <java-symbol type="layout" name="chooser_az_label_row" />
   <java-symbol type="string" name="chooser_all_apps_button_label" />
+  <java-symbol type="anim" name="resolver_close_anim" />
   <java-symbol type="anim" name="resolver_launch_anim" />
   <java-symbol type="style" name="Animation.DeviceDefault.Activity.Resolver" />
 
@@ -5363,5 +5366,12 @@
   <java-symbol type="string" name="satellite_notification_how_it_works" />
   <java-symbol type="drawable" name="ic_satellite_alt_24px" />
 
+  <!-- DisplayManager configs. -->
+  <java-symbol type="bool" name="config_evenDimmerEnabled" />
+
   <java-symbol type="bool" name="config_watchlistUseFileHashesCache" />
+  <java-symbol type="string" name="config_defaultContextualSearchPackageName" />
+  <java-symbol type="string" name="config_defaultContextualSearchKey" />
+  <java-symbol type="string" name="config_defaultContextualSearchEnabled" />
+  <java-symbol type="string" name="config_defaultContextualSearchLegacyEnabled" />
 </resources>
diff --git a/core/res/res/xml/bookmarks.xml b/core/res/res/xml/bookmarks.xml
index 3087aaa..22d0226 100644
--- a/core/res/res/xml/bookmarks.xml
+++ b/core/res/res/xml/bookmarks.xml
@@ -33,7 +33,7 @@
 -->
 <bookmarks>
     <bookmark
-        category="android.intent.category.APP_BROWSER"
+        role="android.app.role.BROWSER"
         shortcut="b" />
     <bookmark
         category="android.intent.category.APP_CONTACTS"
@@ -51,7 +51,7 @@
         category="android.intent.category.APP_MUSIC"
         shortcut="p" />
     <bookmark
-        category="android.intent.category.APP_MESSAGING"
+        role="android.app.role.SMS"
         shortcut="s" />
     <bookmark
         category="android.intent.category.APP_CALCULATOR"
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java
index fbb446b..36a6430 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java
@@ -22,8 +22,8 @@
 import android.hardware.radio.ProgramSelector;
 import android.hardware.radio.RadioManager;
 import android.hardware.radio.UniqueProgramIdentifier;
-import android.test.suitebuilder.annotation.MediumTest;
 
+import androidx.test.filters.MediumTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase;
diff --git a/core/tests/ConnectivityManagerTest/Android.bp b/core/tests/ConnectivityManagerTest/Android.bp
index beaf176..f17a28d 100644
--- a/core/tests/ConnectivityManagerTest/Android.bp
+++ b/core/tests/ConnectivityManagerTest/Android.bp
@@ -27,7 +27,10 @@
         "android.test.runner",
         "android.test.base",
     ],
-    static_libs: ["junit"],
+    static_libs: [
+        "junit",
+        "androidx.test.rules",
+    ],
     // Include all test java files.
     srcs: ["src/**/*.java"],
     platform_apis: true,
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index 2d291ff..32da1d8 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -22,7 +22,8 @@
 import android.net.wifi.WifiManager;
 import android.os.SystemClock;
 import android.provider.Settings;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
 import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
index 23135dd..9443766 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
@@ -22,9 +22,9 @@
 import android.net.wifi.WifiConfiguration.PairwiseCipher;
 import android.net.wifi.WifiConfiguration.Protocol;
 import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
 import android.os.Bundle;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
 import com.android.connectivitymanagertest.WifiAssociationTestRunner;
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
index b37daa3..9c61647 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
@@ -18,7 +18,8 @@
 
 import android.net.wifi.WifiConfiguration;
 import android.os.SystemClock;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
 import com.android.connectivitymanagertest.WifiConfigurationHelper;
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 4b82c3d..993b9ef 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -29,9 +29,10 @@
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.provider.Settings;
-import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
+import androidx.test.filters.LargeTest;
+
 import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
 import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
 import com.android.connectivitymanagertest.WifiConfigurationHelper;
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
index 5c2f388..9dc3fce 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
@@ -17,19 +17,19 @@
 package com.android.connectivitymanagertest.unit;
 
 import android.content.BroadcastReceiver;
+import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.Context;
 import android.net.NetworkInfo;
-import android.net.wifi.WifiManager;
+import android.net.wifi.SupplicantState;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiConfiguration.Status;
-import android.net.wifi.SupplicantState;
-
-import android.test.suitebuilder.annotation.LargeTest;
+import android.net.wifi.WifiManager;
 import android.test.AndroidTestCase;
 
+import androidx.test.filters.LargeTest;
+
 import java.util.List;
 
 /**
diff --git a/core/tests/bandwidthtests/Android.bp b/core/tests/bandwidthtests/Android.bp
index d0b42f7..8645b39 100644
--- a/core/tests/bandwidthtests/Android.bp
+++ b/core/tests/bandwidthtests/Android.bp
@@ -31,6 +31,9 @@
         "org.apache.http.legacy",
         "android.test.base",
     ],
-    static_libs: ["junit"],
+    static_libs: [
+        "junit",
+        "androidx.test.rules",
+    ],
     platform_apis: true,
 }
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
index 4b42f4ae..b2c85a2 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
@@ -30,9 +30,10 @@
 import android.os.SystemClock;
 import android.telephony.TelephonyManager;
 import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
+import androidx.test.filters.LargeTest;
+
 import com.android.bandwidthtest.util.BandwidthTestUtil;
 import com.android.bandwidthtest.util.ConnectionUtil;
 
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 37e6780..e72beee 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -28,10 +28,19 @@
     visibility: ["//visibility:private"],
 }
 
+java_defaults {
+    name: "FrameworksCoreTests-resources",
+    aaptflags: [
+        "-0 .dat",
+        "-0 .gld",
+        "-c fa",
+    ],
+    resource_dirs: ["res"],
+}
+
 android_test {
     name: "FrameworksCoreTests",
-    // FrameworksCoreTestsRavenwood references the .aapt.srcjar
-    use_resource_processor: false,
+    defaults: ["FrameworksCoreTests-resources"],
 
     srcs: [
         "src/**/*.java",
@@ -117,7 +126,6 @@
 
     certificate: "platform",
 
-    resource_dirs: ["res"],
     resource_zips: [":FrameworksCoreTests_apks_as_resources"],
     java_resources: [":FrameworksCoreTests_unit_test_cert_der"],
 
@@ -128,6 +136,24 @@
     ],
 }
 
+// FrameworksCoreTestsRavenwood pulls in the R.java class from this one.
+// Note, "FrameworksCoreTests" and "FrameworksCoreTests-resonly" _might_ not have indentical
+// R.java (not sure if there's a guarantee), but that doesn't matter as long as
+// FrameworksCoreTestsRavenwood consistently uses the R definition in this module.
+android_app {
+    name: "FrameworksCoreTests-resonly",
+    defaults: ["FrameworksCoreTests-resources"],
+
+    // FrameworksCoreTestsRavenwood references the .aapt.srcjar
+    use_resource_processor: false,
+    libs: [
+        "framework-res",
+        "android.test.runner",
+        "org.apache.http.legacy",
+    ],
+    sdk_version: "core_platform",
+}
+
 // Rules to copy all the test apks to the intermediate raw resource directory
 java_genrule {
     name: "FrameworksCoreTests_apks_as_resources",
@@ -225,7 +251,11 @@
         "src/com/android/internal/util/**/*.java",
         "src/com/android/internal/power/EnergyConsumerStatsTest.java",
 
-        ":FrameworksCoreTests{.aapt.srcjar}",
+        // Pull in R.java from FrameworksCoreTests-resonly, not from FrameworksCoreTests,
+        // to avoid having a dependency to FrameworksCoreTests.
+        // This way, when updating source files and running this test, we don't need to
+        // rebuild the entire FrameworksCoreTests, which would be slow.
+        ":FrameworksCoreTests-resonly{.aapt.srcjar}",
         ":FrameworksCoreTests-aidl",
         ":FrameworksCoreTests-helpers",
         ":FrameworksCoreTestDoubles-sources",
diff --git a/core/tests/coretests/src/android/accessibilityservice/BrailleDisplayControllerImplTest.java b/core/tests/coretests/src/android/accessibilityservice/BrailleDisplayControllerImplTest.java
index aaa199d..e8b295b 100644
--- a/core/tests/coretests/src/android/accessibilityservice/BrailleDisplayControllerImplTest.java
+++ b/core/tests/coretests/src/android/accessibilityservice/BrailleDisplayControllerImplTest.java
@@ -22,6 +22,7 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.hardware.usb.UsbDevice;
 import android.platform.test.annotations.RequiresFlagsEnabled;
@@ -58,6 +59,7 @@
     @Rule
     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
 
+    private AccessibilityService mAccessibilityService;
     private BrailleDisplayController mBrailleDisplayController;
 
     @Mock
@@ -76,12 +78,13 @@
     @Before
     public void test() {
         MockitoAnnotations.initMocks(this);
-        AccessibilityService accessibilityService = spy(new TestAccessibilityService());
-        doReturn((Executor) Runnable::run).when(accessibilityService).getMainExecutor();
-        doReturn(TEST_SERVICE_CONNECTION_ID).when(accessibilityService).getConnectionId();
+        mAccessibilityService = spy(new TestAccessibilityService());
+        doReturn((Executor) Runnable::run).when(mAccessibilityService).getMainExecutor();
+        doReturn(TEST_SERVICE_CONNECTION_ID).when(mAccessibilityService).getConnectionId();
         AccessibilityInteractionClient.addConnection(TEST_SERVICE_CONNECTION_ID,
                 mAccessibilityServiceConnection, /*initializeCache=*/false);
-        mBrailleDisplayController = accessibilityService.getBrailleDisplayController();
+        mBrailleDisplayController = new BrailleDisplayControllerImpl(
+                mAccessibilityService, new Object(), /*isHidrawSupported=*/true);
     }
 
     // Automated CTS tests only use the BluetoothDevice version of BrailleDisplayController#connect
@@ -104,4 +107,17 @@
         assertThrows(IllegalStateException.class,
                 () -> mBrailleDisplayController.connect(usbDevice, mBrailleDisplayCallback));
     }
+
+    @Test
+    public void connect_HidrawNotSupported_callsOnConnectionFailed() {
+        BrailleDisplayController controller = new BrailleDisplayControllerImpl(
+                mAccessibilityService, new Object(), /*isHidrawSupported=*/false);
+        UsbDevice usbDevice = Mockito.mock(UsbDevice.class);
+
+        controller.connect(usbDevice, mBrailleDisplayCallback);
+
+        verify(mBrailleDisplayCallback).onConnectionFailed(
+                BrailleDisplayController.BrailleDisplayCallback.FLAG_ERROR_CANNOT_ACCESS);
+        verifyZeroInteractions(mAccessibilityServiceConnection);
+    }
 }
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index a7d083c..927c67c 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -21,16 +21,22 @@
 import static android.content.Intent.ACTION_VIEW;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 
+import static com.android.window.flags.Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+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 android.annotation.NonNull;
@@ -46,6 +52,7 @@
 import android.app.servertransaction.ActivityRelaunchItem;
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.ClientTransactionItem;
+import android.app.servertransaction.ClientTransactionListenerController;
 import android.app.servertransaction.ConfigurationChangeItem;
 import android.app.servertransaction.NewIntentItem;
 import android.app.servertransaction.ResumeActivityItem;
@@ -60,11 +67,14 @@
 import android.hardware.display.VirtualDisplay;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.util.DisplayMetrics;
 import android.util.MergedConfiguration;
 import android.view.Display;
 import android.view.View;
+import android.window.ActivityWindowInfo;
 import android.window.WindowContextInfo;
 import android.window.WindowTokenClientController;
 
@@ -80,11 +90,14 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
 /**
@@ -102,11 +115,17 @@
     // few sequence numbers the framework used to launch the test activity.
     private static final int BASE_SEQ = 10000000;
 
-    @Rule
+    @Rule(order = 0)
     public final ActivityTestRule<TestActivity> mActivityTestRule =
             new ActivityTestRule<>(TestActivity.class, true /* initialTouchMode */,
                     false /* launchActivity */);
 
+    @Rule(order = 1)
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+
+    @Mock
+    private BiConsumer<IBinder, ActivityWindowInfo> mActivityWindowInfoListener;
+
     private WindowTokenClientController mOriginalWindowTokenClientController;
     private Configuration mOriginalAppConfig;
 
@@ -114,6 +133,8 @@
 
     @Before
     public void setup() {
+        MockitoAnnotations.initMocks(this);
+
         // Keep track of the original controller, so that it can be used to restore in tearDown()
         // when there is override in some test cases.
         mOriginalWindowTokenClientController = WindowTokenClientController.getInstance();
@@ -128,6 +149,8 @@
             mCreatedVirtualDisplays = null;
         }
         WindowTokenClientController.overrideForTesting(mOriginalWindowTokenClientController);
+        ClientTransactionListenerController.getInstance()
+                .unregisterActivityWindowInfoChangedListener(mActivityWindowInfoListener);
         InstrumentationRegistry.getInstrumentation().runOnMainSync(
                 () -> restoreConfig(ActivityThread.currentActivityThread(), mOriginalAppConfig));
     }
@@ -246,7 +269,7 @@
             newConfig.smallestScreenWidthDp++;
             transaction = newTransaction(activityThread);
             transaction.addTransactionItem(ActivityConfigurationChangeItem.obtain(
-                    activity.getActivityToken(), newConfig));
+                    activity.getActivityToken(), newConfig, new ActivityWindowInfo()));
             appThread.scheduleTransaction(transaction);
             InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
@@ -394,11 +417,13 @@
             olderConfig.seq = seq + 1;
 
             final ActivityClientRecord r = getActivityClientRecord(activity);
-            activityThread.handleActivityConfigurationChanged(r, olderConfig, INVALID_DISPLAY);
+            activityThread.handleActivityConfigurationChanged(r, olderConfig, INVALID_DISPLAY,
+                    new ActivityWindowInfo());
             assertEquals(numOfConfig, activity.mNumOfConfigChanges);
             assertEquals(olderConfig.orientation, activity.mConfig.orientation);
 
-            activityThread.handleActivityConfigurationChanged(r, newerConfig, INVALID_DISPLAY);
+            activityThread.handleActivityConfigurationChanged(r, newerConfig, INVALID_DISPLAY,
+                    new ActivityWindowInfo());
             assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges);
             assertEquals(newerConfig.orientation, activity.mConfig.orientation);
         });
@@ -416,7 +441,7 @@
             config.orientation = ORIENTATION_PORTRAIT;
 
             activityThread.handleActivityConfigurationChanged(getActivityClientRecord(activity),
-                    config, INVALID_DISPLAY);
+                    config, INVALID_DISPLAY, new ActivityWindowInfo());
         });
 
         final IApplicationThread appThread = activityThread.getApplicationThread();
@@ -452,11 +477,11 @@
 
         transaction = newTransaction(activityThread);
         transaction.addTransactionItem(ActivityConfigurationChangeItem.obtain(
-                activity.getActivityToken(), activityConfigLandscape));
+                activity.getActivityToken(), activityConfigLandscape, new ActivityWindowInfo()));
         transaction.addTransactionItem(ConfigurationChangeItem.obtain(
                 processConfigPortrait, DEVICE_ID_INVALID));
         transaction.addTransactionItem(ActivityConfigurationChangeItem.obtain(
-                activity.getActivityToken(), activityConfigPortrait));
+                activity.getActivityToken(), activityConfigPortrait, new ActivityWindowInfo()));
         appThread.scheduleTransaction(transaction);
 
         activity.mTestLatch.await(TIMEOUT_SEC, TimeUnit.SECONDS);
@@ -487,7 +512,7 @@
             config.orientation = ORIENTATION_PORTRAIT;
 
             activityThread.handleActivityConfigurationChanged(getActivityClientRecord(activity),
-                    config, INVALID_DISPLAY);
+                    config, INVALID_DISPLAY, new ActivityWindowInfo());
         });
 
         final int numOfConfig = activity.mNumOfConfigChanges;
@@ -617,7 +642,7 @@
             activityThread.updatePendingActivityConfiguration(activity.getActivityToken(),
                     newActivityConfig);
             activityThread.handleActivityConfigurationChanged(r, newActivityConfig,
-                    INVALID_DISPLAY);
+                    INVALID_DISPLAY, new ActivityWindowInfo());
 
             assertEquals("Virtual display orientation must not change when activity"
                             + " configuration orientation changes.",
@@ -780,10 +805,105 @@
         verify(windowTokenClientController).onWindowContextWindowRemoved(clientToken);
     }
 
+    @Test
+    public void testActivityWindowInfoChanged_activityLaunch() {
+        mSetFlagsRule.enableFlags(FLAG_ACTIVITY_WINDOW_INFO_FLAG);
+
+        ClientTransactionListenerController.getInstance().registerActivityWindowInfoChangedListener(
+                mActivityWindowInfoListener);
+
+        final Activity activity = mActivityTestRule.launchActivity(new Intent());
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        final ActivityClientRecord activityClientRecord = getActivityClientRecord(activity);
+
+        verify(mActivityWindowInfoListener).accept(activityClientRecord.token,
+                activityClientRecord.getActivityWindowInfo());
+    }
+
+    @Test
+    public void testActivityWindowInfoChanged_activityRelaunch() throws RemoteException {
+        mSetFlagsRule.enableFlags(FLAG_ACTIVITY_WINDOW_INFO_FLAG);
+
+        ClientTransactionListenerController.getInstance().registerActivityWindowInfoChangedListener(
+                mActivityWindowInfoListener);
+
+        final Activity activity = mActivityTestRule.launchActivity(new Intent());
+        final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
+        appThread.scheduleTransaction(newRelaunchResumeTransaction(activity));
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        final ActivityClientRecord activityClientRecord = getActivityClientRecord(activity);
+
+        // The same ActivityWindowInfo won't trigger duplicated callback.
+        verify(mActivityWindowInfoListener).accept(activityClientRecord.token,
+                activityClientRecord.getActivityWindowInfo());
+
+        final Configuration currentConfig = activity.getResources().getConfiguration();
+        final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo();
+        activityWindowInfo.set(true /* isEmbedded */, new Rect(0, 0, 1000, 2000),
+                new Rect(0, 0, 1000, 1000));
+        final ActivityRelaunchItem relaunchItem = ActivityRelaunchItem.obtain(
+                activity.getActivityToken(), null, null, 0,
+                new MergedConfiguration(currentConfig, currentConfig),
+                false /* preserveWindow */, activityWindowInfo);
+        final ClientTransaction transaction = newTransaction(activity);
+        transaction.addTransactionItem(relaunchItem);
+        appThread.scheduleTransaction(transaction);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(mActivityWindowInfoListener).accept(activityClientRecord.token,
+                activityWindowInfo);
+    }
+
+    @Test
+    public void testActivityWindowInfoChanged_activityConfigurationChanged()
+            throws RemoteException {
+        mSetFlagsRule.enableFlags(FLAG_ACTIVITY_WINDOW_INFO_FLAG);
+
+        ClientTransactionListenerController.getInstance().registerActivityWindowInfoChangedListener(
+                mActivityWindowInfoListener);
+
+        final Activity activity = mActivityTestRule.launchActivity(new Intent());
+        final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        clearInvocations(mActivityWindowInfoListener);
+        final Configuration config = new Configuration(activity.getResources().getConfiguration());
+        config.seq++;
+        final Rect taskBounds = new Rect(0, 0, 1000, 2000);
+        final Rect taskFragmentBounds = new Rect(0, 0, 1000, 1000);
+        final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo();
+        activityWindowInfo.set(true /* isEmbedded */, taskBounds, taskFragmentBounds);
+        final ActivityConfigurationChangeItem activityConfigurationChangeItem =
+                ActivityConfigurationChangeItem.obtain(
+                        activity.getActivityToken(), config, activityWindowInfo);
+        final ClientTransaction transaction = newTransaction(activity);
+        transaction.addTransactionItem(activityConfigurationChangeItem);
+        appThread.scheduleTransaction(transaction);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(mActivityWindowInfoListener).accept(activity.getActivityToken(),
+                activityWindowInfo);
+
+        clearInvocations(mActivityWindowInfoListener);
+        final ActivityWindowInfo activityWindowInfo2 = new ActivityWindowInfo();
+        activityWindowInfo2.set(true /* isEmbedded */, taskBounds, taskFragmentBounds);
+        config.seq++;
+        final ActivityConfigurationChangeItem activityConfigurationChangeItem2 =
+                ActivityConfigurationChangeItem.obtain(
+                        activity.getActivityToken(), config, activityWindowInfo2);
+        final ClientTransaction transaction2 = newTransaction(activity);
+        transaction2.addTransactionItem(activityConfigurationChangeItem2);
+        appThread.scheduleTransaction(transaction);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        // The same ActivityWindowInfo won't trigger duplicated callback.
+        verify(mActivityWindowInfoListener, never()).accept(any(), any());
+    }
+
     /**
      * Calls {@link ActivityThread#handleActivityConfigurationChanged(ActivityClientRecord,
-     * Configuration, int)} to try to push activity configuration to the activity for the given
-     * sequence number.
+     * Configuration, int, ActivityWindowInfo)} to try to push activity configuration to the
+     * activity for the given sequence number.
      * <p>
      * It uses orientation to push the configuration and it tries a different orientation if the
      * first attempt doesn't make through, to rule out the possibility that the previous
@@ -802,7 +922,8 @@
         Configuration config = new Configuration();
         config.orientation = ORIENTATION_PORTRAIT;
         config.seq = seq;
-        activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY);
+        activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY,
+                new ActivityWindowInfo());
 
         if (activity.mNumOfConfigChanges > numOfConfig) {
             return config.seq;
@@ -811,7 +932,8 @@
         config = new Configuration();
         config.orientation = ORIENTATION_LANDSCAPE;
         config.seq = seq + 1;
-        activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY);
+        activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY,
+                new ActivityWindowInfo());
 
         return config.seq;
     }
@@ -839,7 +961,7 @@
         final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(
                 activity.getActivityToken(), null, null, 0,
                 new MergedConfiguration(currentConfig, currentConfig),
-                false /* preserveWindow */);
+                false /* preserveWindow */, new ActivityWindowInfo());
         final ResumeActivityItem resumeStateRequest =
                 ResumeActivityItem.obtain(activity.getActivityToken(), true /* isForward */,
                         false /* shouldSendCompatFakeFocus*/);
@@ -866,7 +988,7 @@
     @NonNull
     private static ClientTransaction newStopTransaction(@NonNull Activity activity) {
         final StopActivityItem stopStateRequest = StopActivityItem.obtain(
-                activity.getActivityToken(), 0 /* configChanges */);
+                activity.getActivityToken());
 
         final ClientTransaction transaction = newTransaction(activity);
         transaction.addTransactionItem(stopStateRequest);
@@ -878,7 +1000,7 @@
     private static ClientTransaction newActivityConfigTransaction(@NonNull Activity activity,
             @NonNull Configuration config) {
         final ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(
-                activity.getActivityToken(), config);
+                activity.getActivityToken(), config, new ActivityWindowInfo());
 
         final ClientTransaction transaction = newTransaction(activity);
         transaction.addTransactionItem(item);
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java
index b5e8203..9907397 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java
@@ -40,6 +40,7 @@
 import android.util.MergedConfiguration;
 import android.view.IWindow;
 import android.view.InsetsState;
+import android.window.ActivityWindowInfo;
 import android.window.ClientWindowFrames;
 import android.window.WindowContext;
 import android.window.WindowContextInfo;
@@ -106,7 +107,7 @@
     @Test
     public void testActivityConfigurationChangeItem_getContextToUpdate() {
         final ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem
-                .obtain(mActivityToken, mConfiguration);
+                .obtain(mActivityToken, mConfiguration, new ActivityWindowInfo());
         final Context context = item.getContextToUpdate(mHandler);
 
         assertEquals(mActivity, context);
@@ -116,7 +117,8 @@
     public void testActivityRelaunchItem_getContextToUpdate() {
         final ActivityRelaunchItem item = ActivityRelaunchItem
                 .obtain(mActivityToken, null /* pendingResults */, null  /* pendingNewIntents */,
-                        0 /* configChange */, mMergedConfiguration, false /* preserveWindow */);
+                        0 /* configChange */, mMergedConfiguration, false /* preserveWindow */,
+                        new ActivityWindowInfo());
         final Context context = item.getContextToUpdate(mHandler);
 
         assertEquals(mActivity, context);
@@ -134,7 +136,7 @@
     @Test
     public void testDestroyActivityItem_preExecute() {
         final DestroyActivityItem item = DestroyActivityItem
-                .obtain(mActivityToken, false /* finished */, 123 /* configChanges */);
+                .obtain(mActivityToken, false /* finished */);
         item.preExecute(mHandler);
 
         assertEquals(1, mActivitiesToBeDestroyed.size());
@@ -144,7 +146,7 @@
     @Test
     public void testDestroyActivityItem_postExecute() {
         final DestroyActivityItem item = DestroyActivityItem
-                .obtain(mActivityToken, false /* finished */, 123 /* configChanges */);
+                .obtain(mActivityToken, false /* finished */);
         item.preExecute(mHandler);
         item.postExecute(mHandler, mPendingActions);
 
@@ -154,11 +156,11 @@
     @Test
     public void testDestroyActivityItem_execute() {
         final DestroyActivityItem item = DestroyActivityItem
-                .obtain(mActivityToken, false /* finished */, 123 /* configChanges */);
+                .obtain(mActivityToken, false /* finished */);
         item.execute(mHandler, mActivityClientRecord, mPendingActions);
 
         verify(mHandler).handleDestroyActivity(eq(mActivityClientRecord), eq(false) /* finishing */,
-                eq(123) /* configChanges */, eq(false) /* getNonConfigInstance */, any());
+                eq(false) /* getNonConfigInstance */, any());
     }
 
     @Test
@@ -175,7 +177,7 @@
     @Test
     public void testMoveToDisplayItem_getContextToUpdate() {
         final MoveToDisplayItem item = MoveToDisplayItem
-                .obtain(mActivityToken, DEFAULT_DISPLAY, mConfiguration);
+                .obtain(mActivityToken, DEFAULT_DISPLAY, mConfiguration, new ActivityWindowInfo());
         final Context context = item.getContextToUpdate(mHandler);
 
         assertEquals(mActivity, context);
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
index 213fd7b..77d31a5 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
@@ -22,21 +22,29 @@
 
 import static com.android.window.flags.Flags.FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
+import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerGlobal;
 import android.hardware.display.IDisplayManager;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.view.DisplayInfo;
+import android.window.ActivityWindowInfo;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.window.flags.Flags;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -44,6 +52,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.function.BiConsumer;
+
 /**
  * Tests for {@link ClientTransactionListenerController}.
  *
@@ -62,6 +72,10 @@
     private IDisplayManager mIDisplayManager;
     @Mock
     private DisplayManager.DisplayListener mListener;
+    @Mock
+    private BiConsumer<IBinder, ActivityWindowInfo> mActivityWindowInfoListener;
+    @Mock
+    private IBinder mActivityToken;
 
     private DisplayManagerGlobal mDisplayManager;
     private Handler mHandler;
@@ -91,4 +105,24 @@
 
         verify(mListener).onDisplayChanged(123);
     }
+
+    @Test
+    public void testActivityWindowInfoChangedListener() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG);
+
+        mController.registerActivityWindowInfoChangedListener(mActivityWindowInfoListener);
+        final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo();
+        activityWindowInfo.set(true /* isEmbedded */, new Rect(0, 0, 1000, 2000),
+                new Rect(0, 0, 1000, 1000));
+        mController.onActivityWindowInfoChanged(mActivityToken, activityWindowInfo);
+
+        verify(mActivityWindowInfoListener).accept(mActivityToken, activityWindowInfo);
+
+        clearInvocations(mActivityWindowInfoListener);
+        mController.unregisterActivityWindowInfoChangedListener(mActivityWindowInfoListener);
+
+        mController.onActivityWindowInfoChanged(mActivityToken, activityWindowInfo);
+
+        verify(mActivityWindowInfoListener, never()).accept(any(), any());
+    }
 }
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index c6447be..584fe16 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -39,6 +39,7 @@
 import android.os.IBinder;
 import android.os.PersistableBundle;
 import android.platform.test.annotations.Presubmit;
+import android.window.ActivityWindowInfo;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -81,7 +82,8 @@
 
     @Test
     public void testRecycleActivityConfigurationChangeItem() {
-        testRecycle(() -> ActivityConfigurationChangeItem.obtain(mActivityToken, config()));
+        testRecycle(() -> ActivityConfigurationChangeItem.obtain(mActivityToken, config(),
+                new ActivityWindowInfo()));
     }
 
     @Test
@@ -96,7 +98,7 @@
 
     @Test
     public void testRecycleDestroyActivityItem() {
-        testRecycle(() -> DestroyActivityItem.obtain(mActivityToken, true, 117));
+        testRecycle(() -> DestroyActivityItem.obtain(mActivityToken, true));
     }
 
     @Test
@@ -124,6 +126,7 @@
         final int deviceId = 3;
         final IBinder taskFragmentToken = new Binder();
         final IBinder initialCallerInfoAccessToken = new Binder();
+        final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo();
 
         testRecycle(() -> new LaunchActivityItemBuilder(
                 activityToken, intent, activityInfo)
@@ -142,18 +145,21 @@
                 .setTaskFragmentToken(taskFragmentToken)
                 .setDeviceId(deviceId)
                 .setInitialCallerInfoAccessToken(initialCallerInfoAccessToken)
+                .setActivityWindowInfo(activityWindowInfo)
                 .build());
     }
 
     @Test
     public void testRecycleActivityRelaunchItem() {
         testRecycle(() -> ActivityRelaunchItem.obtain(mActivityToken,
-                resultInfoList(), referrerIntentList(), 42, mergedConfig(), true));
+                resultInfoList(), referrerIntentList(), 42, mergedConfig(), true,
+                new ActivityWindowInfo()));
     }
 
     @Test
     public void testRecycleMoveToDisplayItem() {
-        testRecycle(() -> MoveToDisplayItem.obtain(mActivityToken, 4, config()));
+        testRecycle(() -> MoveToDisplayItem.obtain(mActivityToken, 4, config(),
+                new ActivityWindowInfo()));
     }
 
     @Test
@@ -163,7 +169,7 @@
 
     @Test
     public void testRecyclePauseActivityItemItem() {
-        testRecycle(() -> PauseActivityItem.obtain(mActivityToken, true, true, 5, true, true));
+        testRecycle(() -> PauseActivityItem.obtain(mActivityToken, true, true, true, true));
     }
 
     @Test
@@ -179,7 +185,7 @@
 
     @Test
     public void testRecycleStopItem() {
-        testRecycle(() -> StopActivityItem.obtain(mActivityToken, 4));
+        testRecycle(() -> StopActivityItem.obtain(mActivityToken));
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
index d641659..c1b9efd 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
@@ -32,6 +32,7 @@
 import android.os.IBinder;
 import android.os.PersistableBundle;
 import android.util.MergedConfiguration;
+import android.window.ActivityWindowInfo;
 
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.content.ReferrerIntent;
@@ -134,6 +135,8 @@
         private IBinder mTaskFragmentToken;
         @Nullable
         private IBinder mInitialCallerInfoAccessToken;
+        @NonNull
+        private ActivityWindowInfo mActivityWindowInfo = new ActivityWindowInfo();
 
         LaunchActivityItemBuilder(@NonNull IBinder activityToken, @NonNull Intent intent,
                 @NonNull ActivityInfo info) {
@@ -260,6 +263,13 @@
         }
 
         @NonNull
+        LaunchActivityItemBuilder setActivityWindowInfo(
+                @NonNull ActivityWindowInfo activityWindowInfo) {
+            mActivityWindowInfo.set(activityWindowInfo);
+            return this;
+        }
+
+        @NonNull
         LaunchActivityItem build() {
             return LaunchActivityItem.obtain(mActivityToken, mIntent, mIdent, mInfo,
                     mCurConfig, mOverrideConfig, mDeviceId, mReferrer, mVoiceInteractor,
@@ -267,7 +277,7 @@
                     mActivityOptions != null ? mActivityOptions.getSceneTransitionInfo() : null,
                     mIsForward, mProfilerInfo, mAssistToken, null /* activityClientController */,
                     mShareableActivityToken, mLaunchedFromBubble, mTaskFragmentToken,
-                    mInitialCallerInfoAccessToken);
+                    mInitialCallerInfoAccessToken, mActivityWindowInfo);
         }
     }
 }
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
index adb6f2a..935bc75 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
@@ -306,7 +306,7 @@
         final IBinder token = mock(IBinder.class);
         final ClientTransaction destroyTransaction = ClientTransaction.obtain(null /* client */);
         destroyTransaction.addTransactionItem(
-                DestroyActivityItem.obtain(token, false /* finished */, 0 /* configChanges */));
+                DestroyActivityItem.obtain(token, false /* finished */));
         destroyTransaction.preExecute(mTransactionHandler);
         // The activity should be added to to-be-destroyed container.
         assertEquals(1, activitiesToBeDestroyed.size());
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index aa80013..d451fe5 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -32,6 +32,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
+import android.graphics.Rect;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -40,6 +41,7 @@
 import android.os.PersistableBundle;
 import android.platform.test.annotations.Presubmit;
 import android.platform.test.flag.junit.SetFlagsRule;
+import android.window.ActivityWindowInfo;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -93,8 +95,11 @@
     @Test
     public void testActivityConfigChange() {
         // Write to parcel
+        final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo();
+        activityWindowInfo.set(true /* isEmbedded */, new Rect(0, 0, 500, 1000),
+                new Rect(0, 0, 500, 500));
         ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(
-                mActivityToken, config());
+                mActivityToken, config(), activityWindowInfo);
         writeAndPrepareForReading(item);
 
         // Read from parcel and assert
@@ -108,8 +113,11 @@
     @Test
     public void testMoveToDisplay() {
         // Write to parcel
+        final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo();
+        activityWindowInfo.set(true /* isEmbedded */, new Rect(0, 0, 500, 1000),
+                new Rect(0, 0, 500, 500));
         MoveToDisplayItem item = MoveToDisplayItem.obtain(mActivityToken, 4 /* targetDisplayId */,
-                config());
+                config(), activityWindowInfo);
         writeAndPrepareForReading(item);
 
         // Read from parcel and assert
@@ -147,8 +155,7 @@
 
     @Test
     public void testDestroy() {
-        DestroyActivityItem item = DestroyActivityItem.obtain(mActivityToken, true /* finished */,
-                135 /* configChanges */);
+        DestroyActivityItem item = DestroyActivityItem.obtain(mActivityToken, true /* finished */);
         writeAndPrepareForReading(item);
 
         // Read from parcel and assert
@@ -180,6 +187,9 @@
         bundle.putParcelable("data", new ParcelableData(1));
         final PersistableBundle persistableBundle = new PersistableBundle();
         persistableBundle.putInt("k", 4);
+        final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo();
+        activityWindowInfo.set(true /* isEmbedded */, new Rect(0, 0, 500, 1000),
+                new Rect(0, 0, 500, 500));
 
         final LaunchActivityItem item = new LaunchActivityItemBuilder(
                 activityToken, intent, activityInfo)
@@ -198,6 +208,7 @@
                 .setShareableActivityToken(new Binder())
                 .setTaskFragmentToken(new Binder())
                 .setInitialCallerInfoAccessToken(new Binder())
+                .setActivityWindowInfo(activityWindowInfo)
                 .build();
 
         writeAndPrepareForReading(item);
@@ -214,8 +225,11 @@
         // Write to parcel
         Configuration overrideConfig = new Configuration();
         overrideConfig.assetsSeq = 5;
+        final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo();
+        activityWindowInfo.set(true /* isEmbedded */, new Rect(0, 0, 500, 1000),
+                new Rect(0, 0, 500, 500));
         ActivityRelaunchItem item = ActivityRelaunchItem.obtain(mActivityToken, resultInfoList(),
-                referrerIntentList(), 35, mergedConfig(), true);
+                referrerIntentList(), 35, mergedConfig(), true, activityWindowInfo);
         writeAndPrepareForReading(item);
 
         // Read from parcel and assert
@@ -229,8 +243,7 @@
     public void testPause() {
         // Write to parcel
         PauseActivityItem item = PauseActivityItem.obtain(mActivityToken, true /* finished */,
-                true /* userLeaving */, 135 /* configChanges */, true /* dontReport */,
-                true /* autoEnteringPip */);
+                true /* userLeaving */, true /* dontReport */, true /* autoEnteringPip */);
         writeAndPrepareForReading(item);
 
         // Read from parcel and assert
@@ -257,7 +270,7 @@
     @Test
     public void testStop() {
         // Write to parcel
-        StopActivityItem item = StopActivityItem.obtain(mActivityToken, 14 /* configChanges */);
+        StopActivityItem item = StopActivityItem.obtain(mActivityToken);
         writeAndPrepareForReading(item);
 
         // Read from parcel and assert
@@ -288,10 +301,9 @@
         // Write to parcel
         NewIntentItem callback1 = NewIntentItem.obtain(mActivityToken, new ArrayList<>(), true);
         ActivityConfigurationChangeItem callback2 = ActivityConfigurationChangeItem.obtain(
-                mActivityToken, config());
+                mActivityToken, config(), new ActivityWindowInfo());
 
-        StopActivityItem lifecycleRequest = StopActivityItem.obtain(mActivityToken,
-                78 /* configChanges */);
+        StopActivityItem lifecycleRequest = StopActivityItem.obtain(mActivityToken);
 
         ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
         transaction.addTransactionItem(callback1);
@@ -315,7 +327,7 @@
         // Write to parcel
         NewIntentItem callback1 = NewIntentItem.obtain(mActivityToken, new ArrayList<>(), true);
         ActivityConfigurationChangeItem callback2 = ActivityConfigurationChangeItem.obtain(
-                mActivityToken, config());
+                mActivityToken, config(), new ActivityWindowInfo());
 
         ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
         transaction.addTransactionItem(callback1);
@@ -336,8 +348,7 @@
         mSetFlagsRule.disableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
 
         // Write to parcel
-        StopActivityItem lifecycleRequest = StopActivityItem.obtain(mActivityToken,
-                78 /* configChanges */);
+        StopActivityItem lifecycleRequest = StopActivityItem.obtain(mActivityToken);
 
         ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
         transaction.addTransactionItem(lifecycleRequest);
diff --git a/core/tests/coretests/src/android/app/usage/ParcelableUsageEventListTest.java b/core/tests/coretests/src/android/app/usage/ParcelableUsageEventListTest.java
index 9dce899..da40f2a 100644
--- a/core/tests/coretests/src/android/app/usage/ParcelableUsageEventListTest.java
+++ b/core/tests/coretests/src/android/app/usage/ParcelableUsageEventListTest.java
@@ -29,8 +29,8 @@
 import android.content.res.Configuration;
 import android.os.Parcel;
 import android.os.PersistableBundle;
-import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java b/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java
index fae7148..3618543 100644
--- a/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java
+++ b/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java
@@ -18,8 +18,7 @@
 
 import static junit.framework.Assert.fail;
 
-import android.test.suitebuilder.annotation.SmallTest;
-
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.util.ArrayUtils;
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
index 3ee565f..e118c98d 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
@@ -403,41 +403,4 @@
         }
         assertFalse(allowed);
     }
-
-    /** Return true if the path is in the list of strings. */
-    private boolean isConcurrent(String path) throws Exception {
-        path = new File(path).toPath().toRealPath().toString();
-        return SQLiteDatabase.getConcurrentDatabasePaths().contains(path);
-    }
-
-    @Test
-    public void testDuplicateDatabases() throws Exception {
-        // The two database paths in this test are assumed not to have been opened earlier in this
-        // process.
-
-        // A database path that will be opened twice.
-        final String dbName = "never-used-db.db";
-        final File dbFile = mContext.getDatabasePath(dbName);
-        final String dbPath = dbFile.getPath();
-
-        // A database path that will be opened only once.
-        final String okName = "never-used-ok.db";
-        final File okFile = mContext.getDatabasePath(okName);
-        final String okPath = okFile.getPath();
-
-        SQLiteDatabase db1 = SQLiteDatabase.openOrCreateDatabase(dbFile, null);
-        assertFalse(isConcurrent(dbPath));
-        SQLiteDatabase db2 = SQLiteDatabase.openOrCreateDatabase(dbFile, null);
-        assertTrue(isConcurrent(dbPath));
-        db1.close();
-        assertTrue(isConcurrent(dbPath));
-        db2.close();
-        assertTrue(isConcurrent(dbPath));
-
-        SQLiteDatabase db3 = SQLiteDatabase.openOrCreateDatabase(okFile, null);
-        db3.close();
-        db3 = SQLiteDatabase.openOrCreateDatabase(okFile, null);
-        assertFalse(isConcurrent(okPath));
-        db3.close();
-    }
 }
diff --git a/core/tests/coretests/src/android/hardware/face/FaceSensorConfigurationsTest.java b/core/tests/coretests/src/android/hardware/face/FaceSensorConfigurationsTest.java
index da3a465..b61104d 100644
--- a/core/tests/coretests/src/android/hardware/face/FaceSensorConfigurationsTest.java
+++ b/core/tests/coretests/src/android/hardware/face/FaceSensorConfigurationsTest.java
@@ -27,7 +27,8 @@
 import android.hardware.biometrics.face.SensorProps;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/core/tests/coretests/src/android/hardware/fingerprint/FingerprintSensorConfigurationsTest.java b/core/tests/coretests/src/android/hardware/fingerprint/FingerprintSensorConfigurationsTest.java
index 613089c..f058c16 100644
--- a/core/tests/coretests/src/android/hardware/fingerprint/FingerprintSensorConfigurationsTest.java
+++ b/core/tests/coretests/src/android/hardware/fingerprint/FingerprintSensorConfigurationsTest.java
@@ -27,7 +27,8 @@
 import android.hardware.biometrics.fingerprint.SensorProps;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -38,7 +39,6 @@
 
 import java.util.function.Function;
 
-
 @Presubmit
 @SmallTest
 public class FingerprintSensorConfigurationsTest {
diff --git a/core/tests/coretests/src/android/os/PowerManagerTest.java b/core/tests/coretests/src/android/os/PowerManagerTest.java
index cb281ff..b9a12ad 100644
--- a/core/tests/coretests/src/android/os/PowerManagerTest.java
+++ b/core/tests/coretests/src/android/os/PowerManagerTest.java
@@ -32,6 +32,7 @@
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.flag.junit.RavenwoodFlagsValueProvider;
 import android.platform.test.ravenwood.RavenwoodRule;
 
 import androidx.test.InstrumentationRegistry;
@@ -86,7 +87,8 @@
 
     // Required for RequiresFlagsEnabled and RequiresFlagsDisabled annotations to take effect.
     @Rule
-    public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isUnderRavenwood() ? null
+    public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isOnRavenwood()
+            ? RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule()
             : DeviceFlagsValueProvider.createCheckFlagsRule();
 
     /**
diff --git a/core/tests/coretests/src/android/os/WorkDurationUnitTest.java b/core/tests/coretests/src/android/os/WorkDurationUnitTest.java
index c70da6e..fcdc590 100644
--- a/core/tests/coretests/src/android/os/WorkDurationUnitTest.java
+++ b/core/tests/coretests/src/android/os/WorkDurationUnitTest.java
@@ -22,6 +22,7 @@
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.flag.junit.RavenwoodFlagsValueProvider;
 import android.platform.test.ravenwood.RavenwoodRule;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -40,7 +41,8 @@
 
     // Required for RequiresFlagsEnabled and RequiresFlagsDisabled annotations to take effect.
     @Rule
-    public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isUnderRavenwood() ? null
+    public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isOnRavenwood()
+            ? RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule()
             : DeviceFlagsValueProvider.createCheckFlagsRule();
 
     @Before
diff --git a/core/tests/coretests/src/android/tracing/perfetto/DataSourceTest.java b/core/tests/coretests/src/android/tracing/perfetto/DataSourceTest.java
index d57f1fc..030d420 100644
--- a/core/tests/coretests/src/android/tracing/perfetto/DataSourceTest.java
+++ b/core/tests/coretests/src/android/tracing/perfetto/DataSourceTest.java
@@ -24,15 +24,15 @@
 import static java.nio.file.Files.createTempDirectory;
 
 import android.internal.perfetto.protos.PerfettoTrace;
-import android.tools.common.ScenarioBuilder;
-import android.tools.common.Tag;
-import android.tools.common.io.TraceType;
-import android.tools.device.traces.TraceConfig;
-import android.tools.device.traces.TraceConfigs;
-import android.tools.device.traces.io.ResultReader;
-import android.tools.device.traces.io.ResultWriter;
-import android.tools.device.traces.monitors.PerfettoTraceMonitor;
-import android.tools.device.traces.monitors.TraceMonitor;
+import android.tools.ScenarioBuilder;
+import android.tools.Tag;
+import android.tools.io.TraceType;
+import android.tools.traces.TraceConfig;
+import android.tools.traces.TraceConfigs;
+import android.tools.traces.io.ResultReader;
+import android.tools.traces.io.ResultWriter;
+import android.tools.traces.monitors.PerfettoTraceMonitor;
+import android.tools.traces.monitors.TraceMonitor;
 import android.util.proto.ProtoInputStream;
 import android.util.proto.ProtoOutputStream;
 
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index 8c93fbb..48ba526 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -24,8 +24,10 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
-import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.AdditionalMatchers.and;
+import static org.mockito.AdditionalMatchers.not;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.notNull;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
@@ -36,6 +38,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.view.WindowManager.BadTokenException;
 import android.view.WindowManager.LayoutParams;
+import android.view.inputmethod.ImeTracker;
 import android.widget.TextView;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -96,12 +99,12 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             // test if setVisibility can show IME
             mImeConsumer.onWindowFocusGained(true);
-            mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
+            mController.show(WindowInsets.Type.ime(), true /* fromIme */, ImeTracker.Token.empty());
             mController.cancelExistingAnimations();
             assertTrue((mController.getRequestedVisibleTypes() & WindowInsets.Type.ime()) != 0);
 
             // test if setVisibility can hide IME
-            mController.hide(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
+            mController.hide(WindowInsets.Type.ime(), true /* fromIme */, ImeTracker.Token.empty());
             mController.cancelExistingAnimations();
             assertFalse((mController.getRequestedVisibleTypes() & WindowInsets.Type.ime()) != 0);
         });
@@ -114,8 +117,9 @@
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             // Request IME visible before control is available.
+            final var statsToken = ImeTracker.Token.empty();
             mImeConsumer.onWindowFocusGained(true);
-            mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
+            mController.show(WindowInsets.Type.ime(), true /* fromIme */, statsToken);
 
             // set control and verify visibility is applied.
             InsetsSourceControl control = new InsetsSourceControl(ID_IME,
@@ -124,10 +128,10 @@
             // IME show animation should be triggered when control becomes available.
             verify(mController).applyAnimation(
                     eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(true) /* fromIme */,
-                    any() /* statsToken */);
+                    eq(statsToken));
             verify(mController, never()).applyAnimation(
                     eq(WindowInsets.Type.ime()), eq(false) /* show */, eq(true) /* fromIme */,
-                    any() /* statsToken */);
+                    eq(statsToken));
         });
     }
 
@@ -152,9 +156,9 @@
             // Request IME visible before control is available.
             mImeConsumer.onWindowFocusGained(hasWindowFocus);
             final boolean imeVisible = hasWindowFocus && hasViewFocus;
+            final var statsToken = ImeTracker.Token.empty();
             if (imeVisible) {
-                mController.show(WindowInsets.Type.ime(), true /* fromIme */,
-                        null /* statsToken */);
+                mController.show(WindowInsets.Type.ime(), true /* fromIme */, statsToken);
             }
 
             // set control and verify visibility is applied.
@@ -168,23 +172,25 @@
                 // and expect skip animation state after getAndClearSkipAnimationOnce invoked.
                 mController.onControlsChanged(new InsetsSourceControl[]{ control });
                 verify(control).getAndClearSkipAnimationOnce();
+                // This ends up creating a new request when we gain control,
+                // so the statsToken won't match.
                 verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
                         eq(true) /* show */, eq(false) /* fromIme */,
-                        eq(expectSkipAnim) /* skipAnim */, eq(null) /* statsToken */);
+                        eq(expectSkipAnim) /* skipAnim */, and(not(eq(statsToken)), notNull()));
             }
 
             // If previously hasViewFocus is false, verify when requesting the IME visible next
             // time will not skip animation.
             if (!hasViewFocus) {
-                mController.show(WindowInsets.Type.ime(), true /* fromIme */,
-                        null /* statsToken */);
+                final var statsTokenNext = ImeTracker.Token.empty();
+                mController.show(WindowInsets.Type.ime(), true /* fromIme */, statsTokenNext);
                 mController.onControlsChanged(new InsetsSourceControl[]{ control });
                 // Verify IME show animation should be triggered when control becomes available and
                 // the animation will be skipped by getAndClearSkipAnimationOnce invoked.
                 verify(control).getAndClearSkipAnimationOnce();
                 verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
                         eq(true) /* show */, eq(true) /* fromIme */,
-                        eq(false) /* skipAnim */, eq(null) /* statsToken */);
+                        eq(false) /* skipAnim */, eq(statsTokenNext));
             }
         });
     }
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 1568174..316e191 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -256,7 +256,7 @@
             mController.setSystemDrivenInsetsAnimationLoggingListener(loggingListener);
             mController.getSourceConsumer(ID_IME, ime()).onWindowFocusGained(true);
             // since there is no focused view, forcefully make IME visible.
-            mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
+            mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
             // When using the animation thread, this must not invoke onReady()
             mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
         });
@@ -273,14 +273,14 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             mController.getSourceConsumer(ID_IME, ime()).onWindowFocusGained(true);
             // since there is no focused view, forcefully make IME visible.
-            mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
+            mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
             mController.show(all());
             // quickly jump to final state by cancelling it.
             mController.cancelExistingAnimations();
-            final @InsetsType int types = navigationBars() | statusBars() | ime();
+            @InsetsType final int types = navigationBars() | statusBars() | ime();
             assertEquals(types, mController.getRequestedVisibleTypes() & types);
 
-            mController.hide(ime(), true /* fromIme */, null /* statsToken */);
+            mController.hide(ime(), true /* fromIme */, ImeTracker.Token.empty());
             mController.hide(all());
             mController.cancelExistingAnimations();
             assertEquals(0, mController.getRequestedVisibleTypes() & types);
@@ -295,10 +295,10 @@
         mController.onControlsChanged(new InsetsSourceControl[] { ime });
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             mController.getSourceConsumer(ID_IME, ime()).onWindowFocusGained(true);
-            mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
+            mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
             mController.cancelExistingAnimations();
             assertTrue(isRequestedVisible(mController, ime()));
-            mController.hide(ime(), true /* fromIme */, null /* statsToken */);
+            mController.hide(ime(), true /* fromIme */, ImeTracker.Token.empty());
             mController.cancelExistingAnimations();
             assertFalse(isRequestedVisible(mController, ime()));
             mController.getSourceConsumer(ID_IME, ime()).onWindowFocusLost();
@@ -465,7 +465,7 @@
             assertFalse(mController.getState().peekSource(ID_IME).isVisible());
 
             // Pretend IME is calling
-            mController.show(ime(), true /* fromIme */, null /* statsToken */);
+            mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
 
             // Gaining control shortly after
             mController.onControlsChanged(createSingletonControl(ID_IME, ime()));
@@ -489,7 +489,7 @@
             mController.onControlsChanged(createSingletonControl(ID_IME, ime()));
 
             // Pretend IME is calling
-            mController.show(ime(), true /* fromIme */, null /* statsToken */);
+            mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
 
             assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ime()));
             mController.cancelExistingAnimations();
@@ -567,7 +567,7 @@
             verify(listener, never()).onReady(any(), anyInt());
 
             // Pretend that IME is calling.
-            mController.show(ime(), true /* fromIme */, null /* statsToken */);
+            mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
 
             // Ready gets deferred until next predraw
             mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
@@ -651,7 +651,7 @@
             mController.onControlsChanged(createSingletonControl(ID_IME, ime()));
 
             // Pretend IME is calling
-            mController.show(ime(), true /* fromIme */, null /* statsToken */);
+            mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
 
             InsetsState copy = new InsetsState(mController.getState(), true /* copySources */);
             copy.peekSource(ID_IME).setFrame(0, 1, 2, 3);
@@ -851,7 +851,7 @@
 
             // Showing invisible ime should only causes insets change once.
             clearInvocations(mTestHost);
-            mController.show(ime(), true /* fromIme */, null /* statsToken */);
+            mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
             verify(mTestHost, times(1)).notifyInsetsChanged();
 
             // Sending the same insets state should not cause insets change.
@@ -918,7 +918,7 @@
             assertNull(imeInsetsConsumer.getControl());
 
             // Verify IME requested visibility should be updated to IME consumer from controller.
-            mController.show(ime(), true /* fromIme */, null /* statsToken */);
+            mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
             assertTrue(isRequestedVisible(mController, ime()));
 
             mController.hide(ime());
diff --git a/core/tests/coretests/src/android/view/RoundedCornersTest.java b/core/tests/coretests/src/android/view/RoundedCornersTest.java
index 07ef33a..ec665ad 100644
--- a/core/tests/coretests/src/android/view/RoundedCornersTest.java
+++ b/core/tests/coretests/src/android/view/RoundedCornersTest.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import static android.content.res.Configuration.SCREENLAYOUT_ROUND_NO;
+import static android.content.res.Configuration.SCREENLAYOUT_ROUND_YES;
 import static android.view.RoundedCorner.POSITION_BOTTOM_LEFT;
 import static android.view.RoundedCorner.POSITION_BOTTOM_RIGHT;
 import static android.view.RoundedCorner.POSITION_TOP_LEFT;
@@ -28,22 +30,47 @@
 import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.nullValue;
 import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
 
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.platform.test.annotations.Presubmit;
+import android.util.DisplayMetrics;
 import android.util.Pair;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.R;
+
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 @Presubmit
 public class RoundedCornersTest {
 
+    @Mock
+    DisplayMetrics mMockDisplayMetrics;
+    @Mock
+    Resources mMockResources;
+    @Mock TypedArray mMockTypedArray;
+    Configuration mConfiguration;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mConfiguration = Configuration.EMPTY;
+    }
+
     final RoundedCorners mRoundedCorners = new RoundedCorners(
             new RoundedCorner(POSITION_TOP_LEFT, 10, 10, 10),
             new RoundedCorner(POSITION_TOP_RIGHT, 10, 190, 10),
@@ -199,4 +226,63 @@
         assertThat(RoundedCorners.fromRadii(radius, 200, 300),
                 not(sameInstance(cached)));
     }
+
+    @Test
+    public void testGetRoundedCornerRadius_withRoundDevice_usesDisplayRadiusAsDefault() {
+        final int displayWidth = 400;
+        mConfiguration.screenLayout = SCREENLAYOUT_ROUND_YES;
+        mMockDisplayMetrics.widthPixels = displayWidth;
+
+        when(mMockResources.getConfiguration()).thenReturn(mConfiguration);
+        when(mMockResources.getDisplayMetrics()).thenReturn(mMockDisplayMetrics);
+        when(mMockResources.getStringArray(R.array.config_displayUniqueIdArray))
+                .thenReturn(new String[]{"0"});
+        when(mMockTypedArray.length()).thenReturn(0);
+        when(mMockResources.obtainTypedArray(anyInt())).thenReturn(mMockTypedArray);
+        when(mMockResources.getDimensionPixelSize(R.dimen.rounded_corner_radius))
+                .thenReturn(0);
+
+
+        int radius = RoundedCorners.getRoundedCornerRadius(mMockResources, "0");
+        assertEquals((displayWidth / 2), radius);
+    }
+
+    @Test
+    public void testGetRoundedCornerRadius_withRoundDevice_usesOverlayIfProvided() {
+        final int displayWidth = 400;
+        final int overlayValue = 199;
+        mConfiguration.screenLayout = SCREENLAYOUT_ROUND_YES;
+        mMockDisplayMetrics.widthPixels = displayWidth;
+
+        when(mMockResources.getConfiguration()).thenReturn(mConfiguration);
+        when(mMockResources.getDisplayMetrics()).thenReturn(mMockDisplayMetrics);
+        when(mMockResources.getStringArray(R.array.config_displayUniqueIdArray))
+                .thenReturn(new String[]{"0"});
+        when(mMockTypedArray.length()).thenReturn(0);
+        when(mMockResources.obtainTypedArray(anyInt())).thenReturn(mMockTypedArray);
+        when(mMockResources.getDimensionPixelSize(R.dimen.rounded_corner_radius))
+                .thenReturn(overlayValue);
+
+        int radius = RoundedCorners.getRoundedCornerRadius(mMockResources, "0");
+        assertEquals(overlayValue, radius);
+    }
+
+    @Test
+    public void testGetRoundedCornerRadius_withNonRoundDevice_noDisplayDefault() {
+        final int displayWidth = 400;
+        mConfiguration.screenLayout = SCREENLAYOUT_ROUND_NO;
+        mMockDisplayMetrics.widthPixels = displayWidth;
+
+        when(mMockResources.getConfiguration()).thenReturn(mConfiguration);
+        when(mMockResources.getDisplayMetrics()).thenReturn(mMockDisplayMetrics);
+        when(mMockResources.getStringArray(R.array.config_displayUniqueIdArray))
+                .thenReturn(new String[]{"0"});
+        when(mMockTypedArray.length()).thenReturn(0);
+        when(mMockResources.obtainTypedArray(anyInt())).thenReturn(mMockTypedArray);
+        when(mMockResources.getDimensionPixelSize(R.dimen.rounded_corner_radius))
+                .thenReturn(0);
+
+        int radius = RoundedCorners.getRoundedCornerRadius(mMockResources, "0");
+        assertEquals(0, radius);
+    }
 }
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index 64cbe7f..1a242ef 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -451,7 +451,7 @@
         ViewRootImpl viewRootImpl = new ViewRootImpl(sContext, display);
 
         boolean result = viewRootImpl.performHapticFeedback(
-                HapticFeedbackConstants.CONTEXT_CLICK, true);
+                HapticFeedbackConstants.CONTEXT_CLICK, true, false /* fromIme */);
 
         assertThat(result).isFalse();
     }
@@ -1017,6 +1017,60 @@
         assertEquals(viewRootImpl.isFrameRatePowerSavingsBalanced(), true);
     }
 
+    /**
+     * Test the TextureView heuristic:
+     * 1. Store the last 3 invalidates time - FT1, FT2, FT3.
+     * 2. If FT2-FT1 > 15ms && FT3-FT2 > 15ms -> vote for NORMAL category
+     */
+    @Test
+    @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
+    public void votePreferredFrameRate_applyTextureViewHeuristic() throws InterruptedException {
+        final long delay = 30L;
+
+        TextureView view = new TextureView(sContext);
+        WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
+        wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check
+
+        sInstrumentation.runOnMainSync(() -> {
+            WindowManager wm = sContext.getSystemService(WindowManager.class);
+            Display display = wm.getDefaultDisplay();
+            DisplayMetrics metrics = new DisplayMetrics();
+            display.getMetrics(metrics);
+            wmlp.width = (int) (metrics.widthPixels * 0.9);
+            wmlp.height = (int) (metrics.heightPixels * 0.9);
+            wm.addView(view, wmlp);
+        });
+        sInstrumentation.waitForIdleSync();
+
+        ViewRootImpl viewRootImpl = view.getViewRootImpl();
+
+        sInstrumentation.runOnMainSync(() -> {
+            assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
+                    FRAME_RATE_CATEGORY_NO_PREFERENCE);
+            view.invalidate();
+            assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
+                    FRAME_RATE_CATEGORY_HIGH);
+        });
+
+         // reset the frame rate category counts
+        for (int i = 0; i < 5; i++) {
+            Thread.sleep(delay);
+            sInstrumentation.runOnMainSync(() -> {
+                view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
+                view.invalidate();
+            });
+            sInstrumentation.waitForIdleSync();
+        }
+
+        Thread.sleep(delay);
+        sInstrumentation.runOnMainSync(() -> {
+            view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT);
+            view.invalidate();
+            assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
+                    FRAME_RATE_CATEGORY_NORMAL);
+        });
+    }
+
     @Test
     public void forceInvertOffDarkThemeOff_forceDarkModeDisabled() {
         mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR);
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
index 51eb41c..b60b806f 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
@@ -472,6 +472,26 @@
     }
 
     @Test
+    public void onTouchEvent_doesNothing_viewDisabled() {
+        mTestView1.setEnabled(false);
+
+        final int x1 = (sHwArea1.left + sHwArea1.right) / 2;
+        final int y1 = (sHwArea1.top + sHwArea1.bottom) / 2;
+        MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
+        mHandwritingInitiator.onTouchEvent(stylusEvent1);
+
+        final int x2 = x1 + mHandwritingSlop * 2;
+        final int y2 = y1;
+
+        MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
+        mHandwritingInitiator.onTouchEvent(stylusEvent2);
+
+        // HandwritingInitiator will not request focus if it is disabled.
+        verify(mTestView1, never()).requestFocus();
+        verify(mHandwritingInitiator, never()).startHandwriting(mTestView1);
+    }
+
+    @Test
     public void onTouchEvent_focusView_inputConnectionAlreadyBuilt_stylusMoveOnce_withinHWArea() {
         if (!mInitiateWithoutConnection) {
             mHandwritingInitiator.onInputConnectionCreated(mTestView1);
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java b/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java
index 4f722ce..6ab77dc 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java
@@ -355,7 +355,7 @@
         }
 
         @Override
-        public RemoteViews.RemoteCollectionItems getRemoteCollectionItems() {
+        public RemoteViews.RemoteCollectionItems getRemoteCollectionItems(int capSize) {
             RemoteViews.RemoteCollectionItems.Builder itemsBuilder =
                     new RemoteViews.RemoteCollectionItems.Builder();
             itemsBuilder.setHasStableIds(hasStableIds())
diff --git a/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java b/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java
index 3160428..cb8b0db 100644
--- a/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java
+++ b/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java
@@ -24,9 +24,9 @@
 import android.content.Context;
 import android.os.SystemProperties;
 import android.provider.Settings;
-import android.test.suitebuilder.annotation.SmallTest;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index 39cb616..ed641e0 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -61,6 +61,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.testing.PollingCheck;
 import android.view.WindowManagerGlobal;
+import android.window.ActivityWindowInfo;
 import android.window.SizeConfigurationBuckets;
 
 import androidx.test.annotation.UiThreadTest;
@@ -308,17 +309,17 @@
 
         private void pauseActivity(ActivityClientRecord r) {
             mThread.handlePauseActivity(r, false /* finished */,
-                    false /* userLeaving */, 0 /* configChanges */, false /* autoEnteringPip */,
+                    false /* userLeaving */, false /* autoEnteringPip */,
                     null /* pendingActions */, "test");
         }
 
         private void stopActivity(ActivityClientRecord r) {
-            mThread.handleStopActivity(r, 0 /* configChanges */,
+            mThread.handleStopActivity(r,
                     new PendingTransactionActions(), false /* finalStateRequest */, "test");
         }
 
         private void destroyActivity(ActivityClientRecord r) {
-            mThread.handleDestroyActivity(r, true /* finishing */, 0 /* configChanges */,
+            mThread.handleDestroyActivity(r, true /* finishing */,
                     false /* getNonConfigInstance */, "test");
         }
 
@@ -354,7 +355,7 @@
                     null /* activityOptions */, true /* isForward */, null /* profilerInfo */,
                     mThread /* client */, null /* asssitToken */, null /* shareableActivityToken */,
                     false /* launchedFromBubble */, null /* taskfragmentToken */,
-                    null /* initialCallerInfoAccessToken */);
+                    null /* initialCallerInfoAccessToken */, new ActivityWindowInfo());
         }
 
         @Override
diff --git a/core/tests/systemproperties/Android.bp b/core/tests/systemproperties/Android.bp
index 21aa3c44..ed52ccc 100644
--- a/core/tests/systemproperties/Android.bp
+++ b/core/tests/systemproperties/Android.bp
@@ -14,9 +14,9 @@
     dxflags: ["--core-library"],
     static_libs: [
         "android-common",
-        "frameworks-core-util-lib",
         "androidx.test.rules",
         "androidx.test.ext.junit",
+        "frameworks-core-util-lib",
         "ravenwood-junit",
     ],
     libs: [
diff --git a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
index ea65de0..d98120f 100644
--- a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
+++ b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
@@ -24,7 +24,8 @@
 import static org.junit.Assert.fail;
 
 import android.platform.test.ravenwood.RavenwoodRule;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 1fd1003..1410950 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -72,6 +72,12 @@
     src: "enhanced-confirmation.xml",
 }
 
+prebuilt_etc {
+    name: "package-shareduid-allowlist.xml",
+    sub_dir: "sysconfig",
+    src: "package-shareduid-allowlist.xml",
+}
+
 // Privapp permission whitelist files
 
 prebuilt_etc {
@@ -199,3 +205,8 @@
     name: "services.core.protolog.json",
     srcs: ["services.core.protolog.json"],
 }
+
+filegroup {
+    name: "file-core.protolog.pb",
+    srcs: ["core.protolog.pb"],
+}
diff --git a/data/etc/CleanSpec.mk b/data/etc/CleanSpec.mk
index 783a7ed..fd38d27 100644
--- a/data/etc/CleanSpec.mk
+++ b/data/etc/CleanSpec.mk
@@ -43,6 +43,8 @@
 #$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
 #$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
 #$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/sysconfig/package-shareduid-allowlist.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/sysconfig/package-shareduid-allowlist.xml)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.carrierconfig.xml)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.carrierconfig.xml)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.emergency.xml)
diff --git a/data/etc/core.protolog.pb b/data/etc/core.protolog.pb
new file mode 100644
index 0000000..0415e44
--- /dev/null
+++ b/data/etc/core.protolog.pb
Binary files differ
diff --git a/data/etc/package-shareduid-allowlist.xml b/data/etc/package-shareduid-allowlist.xml
new file mode 100644
index 0000000..2401d4a
--- /dev/null
+++ b/data/etc/package-shareduid-allowlist.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+ -->
+
+<!--
+This XML defines an allowlist for packages that want to join a particular shared-uid.
+If a non-system package that is signed with platform signature, is trying to join a particular
+shared-uid, and not in this list, the installation will fail.
+
+- The "package" XML attribute refers to the app's package name.
+- The "shareduid" XML attribute refers to the shared uid name.
+
+Example usage
+    1. <allow-package-shareduid package="com.example.app" shareduid="android.uid.system"/>
+        Indicates that a package - com.example.app, will be able to join android.uid.system.
+    2. <allow-package-shareduid package="oem.example.app" shareduid="oem.uid.custom"/>
+        Indicates that a package - oem.example.app, will be able to join oem.uid.custom.
+-->
+
+<config>
+    <allow-package-shareduid package="android.test.settings" shareduid="android.uid.system" />
+</config>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 4edfb09..051e73f 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -584,6 +584,8 @@
         <permission name="android.permission.DOMAIN_VERIFICATION_AGENT"/>
         <!-- Permission required for CTS test CtsInputTestCases -->
         <permission name="android.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW" />
+        <!-- Permission required for CTS test - PackageManagerShellCommandInstallTest -->
+        <permission name="android.permission.EMERGENCY_INSTALL_PACKAGES" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 42e3387..0231d3a 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1,4715 +1,4709 @@
 {
-  "version": "1.0.0",
+  "version": "2.0.0",
   "messages": {
-    "-2127842445": {
-      "message": "Clearing startingData for token=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-2121056984": {
-      "message": "%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "-2111539867": {
-      "message": "remove IME snapshot, caller=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-2109936758": {
-      "message": "removeAppToken make exiting: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-2109864870": {
-      "message": "app-release(): mOuter=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-2107721178": {
-      "message": "grantEmbeddedWindowFocus win=%s grantFocus=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-2101985723": {
-      "message": "Failed looking up window session=%s callers=%s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-2093859262": {
-      "message": "setClientVisible: %s clientVisible=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowToken.java"
-    },
-    "-2088209279": {
-      "message": "Notified TransitionController that the display is ready.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-2074882083": {
-      "message": "Content Recording: Unable to retrieve task to start recording for display %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-2072089308": {
-      "message": "Attempted to add window with token that is a sub-window: %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-2072029833": {
-      "message": "Content Recording: Found no matching mirror display for id=%d for DEFAULT_DISPLAY. Nothing to mirror.",
-      "level": "WARN",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-2054442123": {
-      "message": "Setting Intent of %s to %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "-2052051397": {
-      "message": "Clear animatingExit: reason=destroySurface win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-2049725903": {
-      "message": "Task back pressed on root taskId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "-2039580386": {
-      "message": "Attempted to add input method window with unknown token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-2036671725": {
-      "message": "      SKIP: is wallpaper",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-2024464438": {
-      "message": "app-onAnimationFinished(): mOuter=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-2014162875": {
-      "message": "Could not register window container listener token=%s, container=%s",
-      "level": "ERROR",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowContextListenerController.java"
-    },
-    "-2012562539": {
-      "message": "startAnimation(): Notify animation start:",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-2010331310": {
-      "message": "resumeTopActivity: Top activity resumed (dontWaitForPause) %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-1980468143": {
-      "message": "DisplayArea appeared name=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
-    },
-    "-1979455254": {
-      "message": "Launch on display check: allow launch for caller present on the display",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-1976930686": {
-      "message": "Attempted to add Accessibility overlay window with bad token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1973119651": {
-      "message": "SyncGroup %d: Adding to group: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
-    },
-    "-1969928125": {
-      "message": "Animation start for %s, anim=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
-    },
-    "-1963461591": {
-      "message": "Removing %s from %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1963363332": {
-      "message": "Restart top activity process of Task taskId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "-1961637874": {
-      "message": "DeferredDisplayUpdater: applying DisplayInfo immediately",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java"
-    },
-    "-1949279037": {
-      "message": "Attempted to add input method window with bad token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1939861963": {
-      "message": "Create root task displayId=%d winMode=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "-1938839202": {
-      "message": "SURFACE LEAK DESTROY: %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-1938204785": {
-      "message": "Moving existing starting %s from %s to %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1933723759": {
-      "message": "Clear animatingExit: reason=relayoutVisibleWindow win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1924376693": {
-      "message": " Setting Ready-group to %b. group=%s from %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-1918702467": {
-      "message": "onSyncFinishedDrawing %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "-1915280162": {
-      "message": "Attempted to add wallpaper window with bad token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1906387645": {
-      "message": "SURFACE controller=%s alpha=%f HScale=%f, VScale=%f: %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "-1905191109": {
-      "message": "SyncGroup %d: Finished!",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
-    },
-    "-1895337367": {
-      "message": "Delete root task display=%d winMode=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "-1886145147": {
-      "message": "resumeTopActivity: Going to sleep and all paused",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-1885450608": {
-      "message": "Content Recording: Successfully created a ContentRecordingSession for displayId=%d to mirror content from displayId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-1884933373": {
-      "message": "enableScreenAfterBoot: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1872288685": {
-      "message": "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "-1868518158": {
-      "message": "Pending back animation due to another animation is running",
-      "level": "WARN",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "-1868124841": {
-      "message": "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, orientationSensorEnabled=%b, keyguardDrawComplete=%b, windowManagerDrawComplete=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-1868048288": {
-      "message": "Updating to new configuration after starting activity.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityStarter.java"
-    },
-    "-1862269827": {
-      "message": "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "-1844540996": {
-      "message": "  Initial targets: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-1838803135": {
-      "message": "Attempted to set windowing mode to a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1834214907": {
-      "message": "createNonAppWindowAnimations()",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-1828118576": {
-      "message": "SyncGroup %d: Started %sfor listener: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
-    },
-    "-1824578273": {
-      "message": "Reporting new frame to %s: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_RESIZE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1818910559": {
-      "message": "DeferredDisplayUpdater: applied DisplayInfo after deferring",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java"
-    },
-    "-1814361639": {
-      "message": "Set IME snapshot position: (%d, %d)",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-1812743677": {
-      "message": "Display id=%d is ignoring all orientation requests, camera is active and the top activity is eligible for force rotation, return %s,portrait activity: %b, is natural orientation portrait: %b.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "-1810446914": {
-      "message": "Trying to update display configuration for system\/invalid process.",
-      "level": "WARN",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-1800899273": {
-      "message": "applyAnimation: anim=%s transit=%s Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "-1792633344": {
-      "message": "Register task organizer=%s uid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "-1791031393": {
-      "message": "Ensuring correct configuration: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1782453012": {
-      "message": "Checking theme of starting window: 0x%x",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1777196134": {
-      "message": "goodToGo(): No apps to animate, mPendingAnimations=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-1777010776": {
-      "message": "create IME snapshot for %s, buff width=%s, height=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-1768557332": {
-      "message": "removeWallpaperAnimation()",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "-1764792832": {
-      "message": "Start collecting in Transition: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "-1750206390": {
-      "message": "Exception thrown when creating surface for client %s (%s). %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1747461042": {
-      "message": "set mOrientationChanging of %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1740512980": {
-      "message": "Stopping %s: nowVisible=%b animating=%b finishing=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-1730156332": {
-      "message": "Display id=%d rotation changed to %d from %d, lastOrientation=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-1728919185": {
-      "message": "        unrelated invisible sibling %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-1710206702": {
-      "message": "Display id=%d is frozen while keyguard locked, return %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-1707370822": {
-      "message": "Ready to stop: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-1704402370": {
-      "message": "resetTaskIntendedTask: calling finishActivity on %s",
-      "level": "WARN",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
-    },
-    "-1700778361": {
-      "message": "Content Recording: Going ahead with updating recording for display %d to new bounds %s and\/or orientation %d and\/or surface size %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-1699018375": {
-      "message": "Adding activity %s to task %s callers: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "-1679411993": {
-      "message": "setVr2dDisplayId called for: %d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-1671601441": {
-      "message": "attachWindowContextToDisplayContent: calling from non-existing process pid=%d uid=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1670695197": {
-      "message": "Attempted to add presentation window to a non-suitable display.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1647332198": {
-      "message": "remove RecentTask %s when finishing user %d",
-      "level": "INFO",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RecentTasks.java"
-    },
-    "-1643780158": {
-      "message": "Saving original orientation before camera compat, last orientation is %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "-1639406696": {
-      "message": "NOSENSOR override detected",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java"
-    },
-    "-1638958146": {
-      "message": "Removing activity %s from task=%s adding to task=%s Callers=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
-    },
-    "-1633115609": {
-      "message": "Key dispatch not paused for screen off",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-1632122349": {
-      "message": "Changing surface while display frozen: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1631991057": {
-      "message": "Display id=%d is notified that Camera %s is closed but activity is still refreshing. Rescheduling an update.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "-1630752478": {
-      "message": "removeLockedTask: removed %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "-1598452494": {
-      "message": "activityDestroyedLocked: r=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_CONTAINERS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1596995693": {
-      "message": "startAnimation",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-1585311008": {
-      "message": "Bring to front target: %s from %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityStarter.java"
-    },
-    "-1583619037": {
-      "message": "Failed to register MediaProjectionWatcherCallback",
-      "level": "ERROR",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/ScreenRecordingCallbackController.java"
-    },
-    "-1582845629": {
-      "message": "Starting animation on %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_DIMMER",
-      "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java"
-    },
-    "-1575977269": {
-      "message": "Skipping %s: mismatch root %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-1568331821": {
-      "message": "Enabling listeners",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-1567866547": {
-      "message": "Collecting in transition %d: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-1564228464": {
-      "message": "App died while pausing: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-1559645910": {
-      "message": "Looking for task of type=%s, taskAffinity=%s, intent=%s, info=%s, preferredTDA=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-1558137010": {
-      "message": "Config is relaunching invisible activity %s called by %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1554521902": {
-      "message": "showInsets(ime) was requested by different window: %s ",
-      "level": "WARN",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
-    },
-    "-1545962566": {
-      "message": "View server did not start",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1539974875": {
-      "message": "removeAppToken: %s delayed=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1526645239": {
-      "message": "Timeout waiting for drawn: undrawn=%s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1518132958": {
-      "message": "fractionRendered boundsOverSource=%f",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "-1517908912": {
-      "message": "requestScrollCapture: caught exception dispatching to window.token=%s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1501564055": {
-      "message": "Organized TaskFragment is not ready= %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "-1499134947": {
-      "message": "Removing starting %s from %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1497837552": {
-      "message": "onAnimationFinished(): mPendingAnimations=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-1495062622": {
-      "message": "Can't report activity moved to display - client not running, activityRecord=%s, displayId=%d",
-      "level": "WARN",
-      "group": "WM_DEBUG_SWITCH",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1492881555": {
-      "message": "Starting activity when config will change = %b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityStarter.java"
-    },
-    "-1483435730": {
-      "message": "InsetsSource setWin %s for type %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_INSETS",
-      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
-    },
-    "-1480918485": {
-      "message": "Refreshed activity: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1480772131": {
-      "message": "No app or window is requesting an orientation, return %d for display id=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-1478175541": {
-      "message": "No longer animating wallpaper targets!",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/WallpaperController.java"
-    },
-    "-1474602871": {
-      "message": "Launch on display check: disallow launch on virtual display for not-embedded activity.",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-1474292612": {
-      "message": "Could not find task for id: %d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-1471518109": {
-      "message": "Set animatingExit: reason=onAppVisibilityChanged win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1468740466": {
-      "message": "Moving to PAUSED: %s (starting in paused state)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-1452274694": {
-      "message": "      CAN PROMOTE: promoting to parent %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-1449515133": {
-      "message": "Content Recording: stopping active projection for display %d",
-      "level": "ERROR",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-1443029505": {
-      "message": "SAFE MODE ENABLED (menu=%d s=%d dpad=%d trackball=%d)",
-      "level": "INFO",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1442613680": {
-      "message": " Creating Ready-group for Transition %d with root=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-1438175584": {
-      "message": "Input focus has changed to %s display=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/InputMonitor.java"
-    },
-    "-1434147454": {
-      "message": "cleanupAnimation(): Notify animation finished mPendingAnimations=%d reorderMode=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "-1432963966": {
-      "message": "Moving to DESTROYING: %s (destroy requested)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1427184084": {
-      "message": "addWindow: New client %s: window=%s Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1421296808": {
-      "message": "Moving to RESUMED: %s (in existing)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-1419762046": {
-      "message": "moveRootTaskToDisplay: moving taskId=%d to displayId=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-1419461256": {
-      "message": "resumeTopActivity: Resumed %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-1413901262": {
-      "message": "startRecentsActivity(): intent=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "-1410260105": {
-      "message": "Schedule IME show for %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
-    },
-    "-1397175017": {
-      "message": "Other orientation overrides are in place: not reverting",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java"
-    },
-    "-1394745488": {
-      "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_WINDOW_INSETS",
-      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
-    },
-    "-1391944764": {
-      "message": "SURFACE DESTROY: %s. %s",
-      "level": "INFO",
-      "group": "WM_SHOW_SURFACE_ALLOC",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "-1389772804": {
-      "message": "Attempted to add voice interaction window with bad token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1383884640": {
-      "message": " allReady query: used=%b override=%b defer=%d states=[%s]",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-1376035390": {
-      "message": "No task found",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-1364754753": {
-      "message": "Task vanished taskId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "-1352076759": {
-      "message": "Removing app token: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1350198040": {
-      "message": "hideBootMessagesLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1340540100": {
-      "message": "Creating SnapshotStartingData",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1325565952": {
-      "message": "Attempted to get home support flag of a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1323783276": {
-      "message": "performEnableScreen: bootFinished() failed.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1318478129": {
-      "message": "applyAnimation: win=%s anim=%d attr=0x%x a=%s transit=%d type=%d isEntrance=%b Callers %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "-1311436264": {
-      "message": "Unregister task fragment organizer=%s uid=%d pid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "-1305966693": {
-      "message": "Sending position change to %s, onTop: %b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1305791032": {
-      "message": "Moving to STOPPED: %s (stop complete)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1305755880": {
-      "message": "Initial config: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-1304806505": {
-      "message": "Starting new activity %s in new task %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityStarter.java"
-    },
-    "-1303628829": {
-      "message": "**** STARTING EXIT",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
-    },
-    "-1292329638": {
-      "message": "Added starting %s: startingWindow=%s startingView=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1288007399": {
-      "message": "performShowLocked: mDrawState=HAS_DRAWN in %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1277068810": {
-      "message": "startBackNavigation currentTask=%s, topRunningActivity=%s, callbackInfo=%s, currentFocus=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "-1263316010": {
-      "message": "Computed rotation=%s (%d) for display id=%d based on lastOrientation=%s (%d) and oldRotation=%s (%d)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-1259022216": {
-      "message": "SURFACE HIDE ( %s ): %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
-    },
-    "-1258739769": {
-      "message": "onTransactionReady, opening: %s, closing: %s, animating: %s, match: %b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "-1257821162": {
-      "message": "OUT SURFACE %s: copied",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1256520588": {
-      "message": "performEnableScreen: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1253056469": {
-      "message": "Launch on display check: %s launch for userId=%d on displayId=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-1248645819": {
-      "message": "\tAdd container=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-1243510456": {
-      "message": "Dim animation requested: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_DIMMER",
-      "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java"
-    },
-    "-1237827119": {
-      "message": "Schedule remove starting %s startingWindow=%s animate=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1228653755": {
-      "message": "Launch on display check: displayId=%d callingPid=%d callingUid=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-1219773477": {
-      "message": "setInputConsumerEnabled(%s): mCanceled=%b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "-1217596375": {
-      "message": "Content Recording: Display %d has no content and is on, so start recording for state %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-1209762265": {
-      "message": "Registering listener=%s with id=%d for window=%s with %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "-1209252064": {
-      "message": "Clear animatingExit: reason=clearAnimatingFlags win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1207757583": {
-      "message": "startAnimation(): Notify animation start: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "-1204565480": {
-      "message": "Adding display switch to existing collecting transition",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/PhysicalDisplaySwitchTransitionLauncher.java"
-    },
-    "-1198579104": {
-      "message": "Pushing next activity %s out to target's task %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
-    },
-    "-1193946201": {
-      "message": "Can't report activity position update - client not running, activityRecord=%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1187377055": {
-      "message": "Enqueue pending stop if needed: %s wasStopping=%b visibleRequested=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-1185473319": {
-      "message": "ControlAdapter startAnimation mSource: %s controlTarget: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_WINDOW_INSETS",
-      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
-    },
-    "-1164930508": {
-      "message": "Moving to RESUMED: %s (starting new instance) callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "-1156314529": {
-      "message": "Content Recording: Unexpectedly null window container; unable to update recording for display %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-1156118957": {
-      "message": "Updated config=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "-1153814764": {
-      "message": "onAnimationCancelled",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java"
-    },
-    "-1152771606": {
-      "message": "Content Recording: Display %d was already recording, but pause capture since the task is in PIP",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-1145384901": {
-      "message": "shouldWaitAnimatingExit: isTransition: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1142279614": {
-      "message": "Looking for focus: %s, flags=%d, canReceive=%b, reason=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-1136734598": {
-      "message": "Content Recording: Ignoring session on same display %d, with an existing session %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
-    },
-    "-1136467585": {
-      "message": "The listener does not exist.",
-      "level": "INFO",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowContextListenerController.java"
-    },
-    "-1136139407": {
-      "message": "no-history finish of %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1130891072": {
-      "message": "Orientation continue waiting for draw in %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "-1130868271": {
-      "message": "Resizing %s WITH DRAW PENDING",
-      "level": "INFO",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1117599386": {
-      "message": "Deferring rotation, display is not enabled.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-1115019498": {
-      "message": "Configuration & display unchanged in %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1113134997": {
-      "message": "Attempted to add application window with unknown token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1108775960": {
-      "message": "%s is requesting orientation %d (%s)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "-1104347731": {
-      "message": "Setting requested orientation %s for %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1103716954": {
-      "message": "Not removing %s due to exit animation",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1103115659": {
-      "message": "Performing post-rotate rotation",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-1101551167": {
-      "message": "Auto-PIP allowed, entering PIP mode directly: %s, didAutoPip: %b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-1097851684": {
-      "message": "Content Recording: Unable to start recording due to null token for display %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-1089874824": {
-      "message": "SURFACE SHOW (performLayout): %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
-    },
-    "-1075136930": {
-      "message": "startLockTaskMode: Can't lock due to auth",
-      "level": "WARN",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "-1069336896": {
-      "message": "onRootTaskOrderChanged(): rootTask=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "-1060529098": {
-      "message": "  Skipping post-transition snapshot for task %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-1060365734": {
-      "message": "Attempted to add QS dialog window with bad token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1047945589": {
-      "message": "Remove client=%x, surfaceController=%s Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1043981272": {
-      "message": "Reverting orientation. Rotating to %s from %s rather than %s.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-1042574499": {
-      "message": "Attempted to add Accessibility overlay window with unknown token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1033630971": {
-      "message": "onBackNavigationDone backType=%s, triggerBack=%b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "-1028213464": {
-      "message": "%s skipping animation and directly setting alpha=%f, blur=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_DIMMER",
-      "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java"
-    },
-    "-1022146708": {
-      "message": "Skipping %s: mismatch activity type",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-1016578046": {
-      "message": "Moving to %s Relaunching %s callers=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1009117329": {
-      "message": "isFetchingAppTransitionSpecs=true",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "-1005167552": {
-      "message": "Playing #%d in parallel on track #%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "-1003678883": {
-      "message": "Cleaning splash screen token=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1003060523": {
-      "message": "Finish needs to pause: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-993378225": {
-      "message": "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING %s in %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_DRAW",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "-986746907": {
-      "message": "Starting window removed %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-962760979": {
-      "message": "thawRotation: mRotation=%d, caller=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-961053385": {
-      "message": "attachWindowContextToDisplayArea: calling from non-existing process pid=%d uid=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-957060823": {
-      "message": "Moving to PAUSING: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-951939129": {
-      "message": "Unregister task organizer=%s uid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "-948446688": {
-      "message": "Create TaskDisplayArea uid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
-    },
-    "-938271693": {
-      "message": "allResumedActivitiesIdle: rootTask=%d %s not idle",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-937498525": {
-      "message": "Executing finish of failed to pause activity: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-930893991": {
-      "message": "Set sync ready, syncId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
-    },
-    "-929676529": {
-      "message": "Configuration changes for %s, allChanges=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-927199900": {
-      "message": "Updating global configuration to: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-926231510": {
-      "message": "State unchanged from:%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-921346089": {
-      "message": "Content Recording: Unable to tell MediaProjectionManagerService to stop the active projection for display %d: %s",
-      "level": "ERROR",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-917215012": {
-      "message": "%s: caller %d is using old GET_TASKS but privileged; allowing",
-      "level": "WARN",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-916108501": {
-      "message": "Adding %s to %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-914253865": {
-      "message": "Attempted to add voice interaction window with unknown token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-894942237": {
-      "message": "Force Playing Transition: %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-888703350": {
-      "message": "Skipping %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "-883738232": {
-      "message": "Adding more than one toast window for UID at a time.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-877494781": {
-      "message": "Start pushing activity %s out to bottom task %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
-    },
-    "-874888131": {
-      "message": "Set transition ready=%b %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-874446906": {
-      "message": "showBootMessage: msg=%s always=%b mAllowBootMessages=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-874087484": {
-      "message": "SyncGroup %d: Set ready %b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
-    },
-    "-869242375": {
-      "message": "Content Recording: Unable to start recording due to invalid region for display %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-863438038": {
-      "message": "Aborting Transition: %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-861859917": {
-      "message": "Attempted to add window to a display that does not exist: %d. Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-861707633": {
-      "message": "Destroying surface %s called by %s",
-      "level": "INFO",
-      "group": "WM_SHOW_SURFACE_ALLOC",
-      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
-    },
-    "-856750101": {
-      "message": "Launch on display check: allow launch for owner of the display",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-856590985": {
-      "message": "dcTarget: %s mImeRequester: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
-    },
-    "-853404763": {
-      "message": "\twallpaper=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-853226675": {
-      "message": "Attempted to add window with exiting application token .%s Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-846931068": {
-      "message": "Update camera compat control state to %s for taskId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "-846078709": {
-      "message": "Configuration doesn't matter in finishing %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-814760297": {
-      "message": "Looking for task of %s in %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-809771899": {
-      "message": "findFocusedWindow: Reached focused app=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-804217032": {
-      "message": "Skipping config check (will change): %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-799396645": {
-      "message": "Display id=%d is notified that Camera %s is closed, updating rotation.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "-787664727": {
-      "message": "Cannot launch dream activity due to invalid state. dream component: %s packageName: %s",
-      "level": "ERROR",
-      "group": "WM_DEBUG_DREAM",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-784959154": {
-      "message": "Attempted to add private presentation window to a non-private display.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-783405930": {
-      "message": "Performing post-rotate rotation",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-779535710": {
-      "message": "Transition %d: Set %s as transient-launch",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-779095785": {
-      "message": "        sibling is a participant with mode %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-778347463": {
-      "message": "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b mDisplayFrozen=%b callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-775004869": {
-      "message": "Not a match: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-774908272": {
-      "message": "Marking #%d animation as SYNC.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "-771177730": {
-      "message": "Removing focused app token:%s displayId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-767091913": {
-      "message": "Content Recording: Handle incoming session on display %d, with a pre-existing session %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
-    },
-    "-766059044": {
-      "message": "Display id=%d selected orientation %s (%d), got rotation %s (%d)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-760801764": {
-      "message": "onAnimationCancelled",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
-    },
-    "-760764543": {
-      "message": "Focus not requested for window=%s because it has no surface or is not focusable.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/InputMonitor.java"
-    },
-    "-754503024": {
-      "message": "Relayout %s: oldVis=%d newVis=%d. %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-743856570": {
-      "message": "shouldWaitAnimatingExit: isAnimating: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-743431900": {
-      "message": "Configuration no differences in %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-732715767": {
-      "message": "Unable to retrieve window container to start recording for display %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-729530161": {
-      "message": "Moving to DESTROYED: %s (no app)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-711194343": {
-      "message": "Setting Activity.mLauncherTaskBehind to false. Activity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "-706481945": {
-      "message": "TaskFragment parent info changed name=%s parentTaskId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "-705939410": {
-      "message": "Waiting for pause to complete...",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-703543418": {
-      "message": "      check sibling %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-702650156": {
-      "message": "Override with TaskFragment remote animation for transit=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "-701167286": {
-      "message": "applyAnimation: transit=%s, enter=%b, wc=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "-694710814": {
-      "message": "Pausing rotation during drag",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DragState.java"
-    },
-    "-692907078": {
-      "message": "Handling the deferred animation after transition finished",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "-677449371": {
-      "message": "moveTaskToRootTask: moving task=%d to rootTaskId=%d toTop=%b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-672355406": {
-      "message": "  Rejecting as no-op: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-668956537": {
-      "message": "  THUMBNAIL %s: CREATE",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/SurfaceFreezer.java"
-    },
-    "-666510420": {
-      "message": "With display frozen, orientationChangeComplete=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-658964693": {
-      "message": "onWindowAnimationFinished, wc=%s, type=%s, imeSnapshot=%s, target=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-655104359": {
-      "message": "Frontmost changed immersion: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IMMERSIVE",
-      "at": "com\/android\/server\/wm\/ActivityClientController.java"
-    },
-    "-653156702": {
-      "message": "createAppAnimations()",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-648891906": {
-      "message": "Activity not running or entered PiP, resuming next.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-641258376": {
-      "message": "realStartActivityLocked: Skipping start of r=%s some activities pausing...",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-639217716": {
-      "message": "setFocusedApp %s displayId=%d Callers=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-637815408": {
-      "message": "Invalid surface rotation angle in config_deviceTabletopRotations: %d",
-      "level": "ERROR",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-636553602": {
-      "message": "commitVisibility: %s: visible=%b visibleRequested=%b, isInTransition=%b, runningAnimation=%b, caller=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-635082269": {
-      "message": "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b wallEnabled=%b haveKeyguard=%b",
-      "level": "INFO",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-627759820": {
-      "message": "Display id=%d is notified that Camera %s is open for package %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "-622997754": {
-      "message": "postWindowRemoveCleanupLocked: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-622017164": {
-      "message": "Finish Transition: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "-597091183": {
-      "message": "Delete TaskDisplayArea uid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
-    },
-    "-593535526": {
+    "7286191062634870297": {
       "message": "Binding proc %s with config %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/am\/ActivityManagerService.java"
     },
-    "-584061725": {
-      "message": "Content Recording: Accept session updating same display %d with granted consent, with an existing session %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
-    },
-    "-583031528": {
-      "message": "%s",
-      "level": "INFO",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-576070986": {
-      "message": "Performing post-rotate rotation after seamless rotation",
-      "level": "INFO",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-567946587": {
-      "message": "Requested redraw for orientation change: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-561092364": {
-      "message": "onPointerDownOutsideFocusLocked called on %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-549028919": {
-      "message": "enableScreenIfNeededLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-548282316": {
-      "message": "setLockTaskMode: Locking to %s Callers=%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "-547111355": {
-      "message": "hideIme Control target: %s ",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-545190927": {
-      "message": "<<< CLOSE TRANSACTION animate",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowAnimator.java"
-    },
-    "-542756093": {
-      "message": "TaskFragment vanished name=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "-532081937": {
-      "message": "  Commit activity becoming invisible: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-529187878": {
-      "message": "Reverting orientation after camera compat force rotation",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "-521613870": {
-      "message": "App died during pause, not stopping: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-519504830": {
-      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s isEntrance=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "-517666355": {
-      "message": "Content Recording: Display %d has content (%b) so pause recording",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-509601642": {
-      "message": "    checking %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-507657818": {
-      "message": "Window %s is already added",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-503656156": {
-      "message": "Update process config of %s to new config %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-497620140": {
-      "message": "Transaction ready, syncId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
-    },
-    "-496681057": {
-      "message": "Attempted to get remove mode of a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-484194149": {
-      "message": "no-history finish of %s on new resume",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-483957611": {
-      "message": "Resuming configuration dispatch for %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-481924678": {
-      "message": "handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w.isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_KEEP_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-479665533": {
-      "message": "DisplayRotationCompatPolicy: Multi-window toast not shown as package '%s' cannot be found.",
-      "level": "ERROR",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "-464564167": {
-      "message": "Current transition prevents automatic focus change",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-463348344": {
-      "message": "Removing and adding activity %s to root task at top callers=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "-451552570": {
-      "message": "Current focused window being animated by recents. Overriding back callback to recents controller callback.",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "-449118559": {
-      "message": "Trying to update display configuration for invalid process, pid=%d",
-      "level": "WARN",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-445944810": {
-      "message": "finish(%b): mCanceled=%b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "-443173857": {
-      "message": "Moving pending starting from %s to %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-439951996": {
-      "message": "Disabling listeners",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-436553282": {
-      "message": "Remove sleep token: tag=%s, displayId=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-417730399": {
-      "message": "Preparing to sync a window that was already in the sync, so try dropping buffer. win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-415865166": {
-      "message": "findFocusedWindow: Found new focus @ %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-415346336": {
-      "message": "DeferredDisplayUpdater: partially applying DisplayInfo immediately",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java"
-    },
-    "-401282500": {
-      "message": "destroyIfPossible: r=%s destroy returned removed=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_CONTAINERS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-401029526": {
-      "message": "%s: caller %d does not hold REAL_GET_TASKS; limiting output",
-      "level": "WARN",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-399343789": {
-      "message": "Skipping %s: different user",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-393505149": {
-      "message": "unable to update pointer icon",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-386552155": {
-      "message": "Attempted to set system decors flag to a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-384639879": {
-      "message": "Acquiring screen wakelock due to %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_KEEP_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-381475323": {
-      "message": "DisplayContent: boot is waiting for window of type %d to be drawn",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-379068494": {
-      "message": "unknownApps is not empty: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "-376950429": {
-      "message": "DeferredDisplayUpdater: deferring DisplayInfo update",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java"
-    },
-    "-374767836": {
-      "message": "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-373110070": {
-      "message": "Skipping task: (mismatch activity\/task) %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-360208282": {
-      "message": "Animating wallpapers: old: %s hidden=%b new: %s hidden=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/WallpaperController.java"
-    },
-    "-354571697": {
-      "message": "Existence Changed in transition %d: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-353495930": {
-      "message": "TaskFragmentTransaction changes are not collected in transition because there is an ongoing sync for applySyncTransaction().",
-      "level": "WARN",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
-    },
-    "-347866078": {
-      "message": "Setting move animation on %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-344488673": {
-      "message": "Finishing drawing window %s: mDrawState=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "-322743468": {
-      "message": "setInputMethodInputTarget %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-322035974": {
-      "message": "App freeze timeout expired.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-319689203": {
-      "message": "Reparenting to original parent: %s for %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
-    },
-    "-317761482": {
-      "message": "Create sleep token: tag=%s, displayId=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-317194205": {
-      "message": "clearLockedTasks: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "-315778658": {
-      "message": "transferTouchGesture failed because args transferFromToken or transferToToken is null",
-      "level": "ERROR",
-      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-312353598": {
-      "message": "Executing finish of activity: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-310337305": {
-      "message": "Activity config changed during resume: %s, new next: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-304728471": {
-      "message": "New wallpaper: target=%s prev=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/WallpaperController.java"
-    },
-    "-302468788": {
-      "message": "Expected target rootTask=%s to be top most but found rootTask=%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "-292790591": {
-      "message": "Attempted to set IME policy to a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-275077723": {
-      "message": "New animation: %s old animation: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/WallpaperController.java"
-    },
-    "-266707683": {
-      "message": "Moving #%d from collecting to waiting.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "-251259736": {
-      "message": "No longer freezing: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-248761393": {
-      "message": "startPausing: taskFrag =%s mResumedActivity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-240296576": {
-      "message": "handleAppTransitionReady: displayId=%d appTransition={%s} openingApps=[%s] closingApps=[%s] transit=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "-235225312": {
-      "message": "Skipping config check for initializing activity: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-233530384": {
-      "message": "Content Recording: Incoming session on display %d can't be set since it is already null; the corresponding VirtualDisplay must have already been removed.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
-    },
-    "-230587670": {
-      "message": "SyncGroup %d:  Unfinished container: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
-    },
-    "-228813488": {
-      "message": "%s: Setting back callback %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-208825711": {
-      "message": "shouldWaitAnimatingExit: isWallpaperTarget: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-208664771": {
-      "message": "Reparenting to leash for %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
-    },
-    "-203358733": {
-      "message": "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "-198463978": {
-      "message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-195654020": {
-      "message": "Attempt to transfer touch gesture with host window not associated with embedded window",
-      "level": "WARN",
-      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
-      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
-    },
-    "-193782861": {
-      "message": "Final remove of window: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_MOVEMENT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-186693085": {
-      "message": "Starting a Recents transition which can be parallel.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-182877285": {
-      "message": "Wallpaper layer changed: assigning layers + relayout",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-180594244": {
-      "message": "Content Recording: Unable to tell MediaProjectionManagerService about visibility change on the active projection: %s",
-      "level": "ERROR",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-177040661": {
-      "message": "Start rotation animation. customAnim=%s, mCurRotation=%s, mOriginalRotation=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
-    },
-    "-172326720": {
-      "message": "Saving icicle of %s: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-168799453": {
-      "message": "Allowing features %d:0x%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-167822951": {
-      "message": "Attempted to add starting window to token with already existing starting window",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-163974242": {
-      "message": "setFinishTaskTransaction(%d): transaction=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "-143556958": {
-      "message": "resumeNextFocusableActivityWhenRootTaskIsEmpty: %s, go home",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "-125383273": {
-      "message": "Content Recording: waiting to record, so do nothing",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-124316973": {
-      "message": "Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-116086365": {
-      "message": "******************** ENABLING SCREEN!",
-      "level": "INFO",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-108977760": {
-      "message": "Sandbox max bounds for uid %s to bounds %s. config to never sandbox = %s, config to always sandbox = %s, letterboxing from mismatch with parent bounds = %s, has mCompatDisplayInsets = %s, should create compatDisplayInsets = %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-106400104": {
-      "message": "Preload recents with %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "-98422345": {
-      "message": "Focus window is closing.",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "-91393839": {
-      "message": "Set animatingExit: reason=remove\/applyAnimation win=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-87705714": {
-      "message": "findFocusedWindow: focusedApp=null using new focus @ %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-86763148": {
-      "message": "  KILL SURFACE SESSION %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/Session.java"
-    },
-    "-81260230": {
-      "message": "Display id=%d is notified that Camera %s is closed, scheduling rotation update.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "-81121442": {
-      "message": "ImeContainer just became organized but it doesn't have a parent or the parent doesn't have a surface control. mSurfaceControl=%s imeParentSurfaceControl=%s",
-      "level": "ERROR",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-80004683": {
-      "message": "Resume failed; resetting state to %s: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-70719599": {
-      "message": "Unregister remote animations for organizer=%s uid=%d pid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "-57750640": {
-      "message": "show IME snapshot, ime target=%s, callers=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-57572004": {
-      "message": "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b  canCustomizeAppTransition=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "-55185509": {
-      "message": "setFocusedTask: taskId=%d touchedActivity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-50336993": {
-      "message": "moveFocusableActivityToTop: activity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-33096143": {
-      "message": "applyAnimation: transition animation is disabled or skipped. container=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "-32102932": {
-      "message": "Error sending initial configuration change to WindowContainer overlay",
-      "level": "ERROR",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "-21399771": {
-      "message": "activity %s already destroying, skipping request with reason:%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-8483143": {
-      "message": "No root task above target root task=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "-4263657": {
-      "message": "Got a buffer for request id=%d but latest request is id=%d. Since the buffer is out-of-date, drop it. win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1877956": {
-      "message": "Content Recording: Display %d should start recording, but don't yet since the task is in PIP",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "3593205": {
-      "message": "commitVisibility: %s: visible=%b mVisibleRequested=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WallpaperWindowToken.java"
-    },
-    "9803449": {
-      "message": "startFreezingDisplayLocked: exitAnim=%d enterAnim=%d called by %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "10608884": {
-      "message": "  FREEZE %s: CREATE",
-      "level": "INFO",
-      "group": "WM_SHOW_SURFACE_ALLOC",
-      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
-    },
-    "11060725": {
-      "message": "Attempted to get system decors flag of a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "17696244": {
-      "message": "startAnimation(): mPendingStart=%b mCanceled=%b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "33989965": {
-      "message": " Met condition %s for #%d (%d left)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "34106798": {
-      "message": "Content Recording: Display %d state was (%d), is now (%d), so update recording?",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "34682671": {
-      "message": "Not moving display (displayId=%d) to top. Top focused displayId=%d. Reason: FLAG_STEAL_TOP_FOCUS_DISABLED",
-      "level": "INFO",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "35398067": {
-      "message": "goodToGo(): onAnimationStart, transit=%s, apps=%d, wallpapers=%d, nonApps=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "45285419": {
-      "message": "startingWindow was set but startingSurface==null, couldn't remove",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "51200510": {
-      "message": "  BLACK %s: DESTROY",
-      "level": "INFO",
-      "group": "WM_SHOW_SURFACE_ALLOC",
-      "at": "com\/android\/server\/wm\/BlackFrame.java"
-    },
-    "51628177": {
-      "message": "Attempted to get windowing mode of a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "51927339": {
-      "message": "Skipping %s: voice session",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "61363198": {
-      "message": "Auto-PIP allowed, requesting PIP mode via requestStartTransition(): %s, willAutoPip: %b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "74885950": {
-      "message": "Waiting for top state to be released by %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "83950285": {
-      "message": "removeAnimation(%d)",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "95216706": {
-      "message": "hideIme target: %s ",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "95902367": {
-      "message": "Relayout of %s: focusMayChange=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "100936473": {
-      "message": "Wallpaper animation!",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "102618780": {
-      "message": "resumeTopActivity: Pausing %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "108170907": {
-      "message": "Add starting %s: startingData=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "112145970": {
-      "message": "      SKIP: its sibling was rejected",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "114070759": {
-      "message": "New wallpaper target: %s prevTarget: %s caller=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/WallpaperController.java"
-    },
-    "115358443": {
-      "message": "Focus changing: %s -> %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "138097009": {
-      "message": "NOSENSOR override is absent: reverting",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java"
-    },
-    "140319294": {
-      "message": "IME target changed within ActivityRecord",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
-    },
-    "146871307": {
-      "message": "Tried to remove starting window but startingWindow was null: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "150351993": {
-      "message": "addWindow: %s startingWindow=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "152914409": {
-      "message": "  BLACK %s: CREATE layer=%d",
-      "level": "INFO",
-      "group": "WM_SHOW_SURFACE_ALLOC",
-      "at": "com\/android\/server\/wm\/BlackFrame.java"
-    },
-    "155482615": {
-      "message": "Focus requested for window=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/InputMonitor.java"
-    },
-    "174572959": {
-      "message": "DisplayArea info changed name=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
-    },
-    "182319432": {
-      "message": "        remove from targets %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "184362060": {
-      "message": "screenshotTask(%d): mCanceled=%b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "184610856": {
-      "message": "Start calculating TransitionInfo based on participants: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "186668272": {
-      "message": "Now changing app %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "189628502": {
-      "message": "Moving to STOPPING: %s (stop requested)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "191486492": {
-      "message": "handleNotObscuredLocked: %s was holding screen wakelock but no longer has FLAG_KEEP_SCREEN_ON!!! called by%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_KEEP_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "200829729": {
-      "message": "ScreenRotationAnimation onAnimationEnd",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
-    },
-    "202263690": {
-      "message": "rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "210750281": {
-      "message": "applyAnimationUnchecked, control: %s, task: %s, transit: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "215077284": {
-      "message": "Animation start delayed for %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
-    },
-    "221540118": {
-      "message": "mUserActivityTimeout set to %d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_KEEP_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "232317536": {
-      "message": "Set intercept back pressed on root=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "240271590": {
-      "message": "moveFocusableActivityToTop: unfocusable activity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "241961619": {
-      "message": "Adding %s to %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowToken.java"
-    },
-    "246676969": {
-      "message": "Attempted to add window with non-application token .%s Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "248210157": {
-      "message": "Finishing remote animation",
-      "level": "INFO",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "251812577": {
-      "message": "Register display organizer=%s uid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
-    },
-    "254883724": {
-      "message": "addWindowToken: Attempted to add binder token: %s for already created window token: %s displayId=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "255339989": {
-      "message": "setFocusedRootTask: taskId=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "255692476": {
-      "message": "**** GOOD TO GO",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "259206414": {
-      "message": "Creating Transition: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "261227010": {
-      "message": "Content Recording: Unable to tell log windowing mode change: %s",
-      "level": "ERROR",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "269576220": {
-      "message": "Resuming rotation after drag",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DragState.java"
-    },
-    "269976641": {
-      "message": "goodToGo(): Animation canceled already",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "273212558": {
-      "message": "    info=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "274773837": {
-      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL transit=%s Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "283489582": {
-      "message": "Clear animatingExit: reason=exitAnimationDone win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "288485303": {
-      "message": "Attempted to set remove mode to a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "289967521": {
-      "message": "Check opening app=%s: allDrawn=%b startingDisplayed=%b startingMoved=%b isRelaunching()=%b startingWindow=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "292904800": {
-      "message": "Deferring rotation, animation in progress.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "295861935": {
-      "message": "startLockTaskMode: %s",
-      "level": "WARN",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "302969511": {
-      "message": "Task info changed taskId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "302992539": {
-      "message": "addAnimation(%s)",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "306524472": {
-      "message": "Stop failed; moving to STOPPED: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "312030608": {
-      "message": "New topFocusedDisplayId=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "315395835": {
-      "message": "Trying to add window with invalid user=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "323235828": {
-      "message": "Delaying app transition for recents animation to finish",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "327461496": {
-      "message": "Complete pause: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "339482207": {
-      "message": "Content Recording: Display %d was already recording, so apply transformations if necessary",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "341055768": {
-      "message": "resumeTopActivity: Skip resume: need to start pausing",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "341360111": {
-      "message": "selectAnimation in %s: transit=%d",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
-    },
-    "342460966": {
-      "message": "DRAG %s: pos=(%d,%d)",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/DragState.java"
-    },
-    "344795667": {
-      "message": "*** APP TRANSITION TIMEOUT. displayId=%d isTransitionSet()=%b mOpeningApps.size()=%d mClosingApps.size()=%d mChangingApps.size()=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "350168164": {
-      "message": "Removing activity %s, reason= %s callers=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "355720268": {
-      "message": "stopFreezingDisplayLocked: Unfreezing now",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "360319850": {
-      "message": "fractionRendered scale=%f",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "364992694": {
-      "message": "freezeDisplayRotation: current rotation=%d, new rotation=%d, caller=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "371173718": {
-      "message": "finishSync cancel=%b for %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "371641947": {
-      "message": "Window Manager Crash %s",
-      "level": "WTF",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "372792199": {
-      "message": "Non-null activity for system window of rootType=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "374506950": {
-      "message": "Reporting activity moved to display, activityRecord=%s, displayId=%d, config=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SWITCH",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "374972436": {
-      "message": "performEnableScreen: Waiting for anim complete",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "378825104": {
-      "message": "Enqueueing pending pause: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "378890013": {
-      "message": "Apply and finish immediately because player is disabled for transition #%d .",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "385237117": {
-      "message": "moveFocusableActivityToTop: already on top and focused, activity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "385595355": {
-      "message": "Starting animation on %s: type=%d, anim=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "390947100": {
-      "message": "Screenshotting %s [%s]",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "397382873": {
-      "message": "Moving to PAUSED: %s %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "397862437": {
-      "message": "Cancelling animation restarting=%b for %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
-    },
-    "399841913": {
-      "message": "SURFACE RECOVER DESTROY: %s",
-      "level": "INFO",
-      "group": "WM_SHOW_SURFACE_ALLOC",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "405146734": {
-      "message": "  Final targets: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "416924848": {
-      "message": "InsetsSource Control %s for target %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_INSETS",
-      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
-    },
-    "417311568": {
-      "message": "onResize: Resizing %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RESIZE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "419378610": {
-      "message": "Content Recording: Apply transformations of shift %d x %d, scale %f x %f, crop (aka recorded content size) %d x %d for display %d; display has size %d x %d; surface has size %d x %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "422634333": {
-      "message": "First draw done in potential wallpaper target %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "424524729": {
-      "message": "Attempted to add wallpaper window with unknown token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "431715812": {
-      "message": "Launch on display check: allow launch any on display",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "435494046": {
-      "message": "Attempted to add window to a display for which the application does not have access: %d.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "463993897": {
-      "message": "Aborted waiting for drawn: %s",
-      "level": "WARN",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "485170982": {
-      "message": "Not finishing noHistory %s on stop because we're just sleeping",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "487621047": {
-      "message": "DisplayArea vanished name=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
-    },
-    "508887531": {
-      "message": "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "528150092": {
-      "message": "        keep as target %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "531242746": {
-      "message": "  THUMBNAIL %s: CREATE",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowContainerThumbnail.java"
-    },
-    "531891870": {
-      "message": "Previous Destination is Activity:%s Task:%s removedContainer:%s, backType=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "532771960": {
-      "message": "Adding untrusted state listener=%s with id=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "535103992": {
-      "message": "Wallpaper may change!  Adjusting",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "539077569": {
-      "message": "Clear freezing of %s force=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "544101314": {
-      "message": "performEnableScreen: Waited %dms for all windows to be drawn",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "556758086": {
-      "message": "Applying new update lock state '%s' for %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IMMERSIVE",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "557227556": {
-      "message": "onAnimationFinished(): Notify animation finished:",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "558823034": {
-      "message": "SURFACE isOpaque=%b: %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
-    },
-    "573582981": {
-      "message": "reparent: moving activity=%s to new task fragment in task=%d at %d",
-      "level": "INFO",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "579298675": {
-      "message": "Moving to DESTROYED: %s (removed from history)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "585096182": {
-      "message": "SURFACE isColorSpaceAgnostic=%b: %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
-    },
-    "585839596": {
-      "message": "call showInsets(ime) on %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
-    },
-    "594260577": {
-      "message": "createWallpaperAnimations()",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "600140673": {
-      "message": "checkBootAnimationComplete: Waiting for anim complete",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "601283564": {
-      "message": "Dream packageName does not match active dream. Package %s does not match %s",
-      "level": "ERROR",
-      "group": "WM_DEBUG_DREAM",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "605179032": {
-      "message": "checkIfInThreshold fractionRendered=%f alpha=%f currTimeMs=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "608694300": {
-      "message": "  NEW SURFACE SESSION %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/Session.java"
-    },
-    "612856628": {
-      "message": "Content Recording: Stop MediaProjection on virtual display %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "620519522": {
-      "message": "findFocusedWindow: No focusable windows, display=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "628276090": {
-      "message": "Delaying app transition for screen rotation animation to finish",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "631792420": {
-      "message": "Attempted to add window with token that is not a window: %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "638429464": {
-      "message": "\tRemove container=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "644675193": {
-      "message": "Real start recents",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "646155519": {
-      "message": "Started intent=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "646981048": {
-      "message": "Invalid displayId for requestScrollCapture: %d",
-      "level": "ERROR",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "662572728": {
-      "message": "Attempted to add a toast window with bad token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "665256544": {
-      "message": "All windows drawn!",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "666937535": {
-      "message": "attachWindowContextToDisplayArea: trying to attach to a non-existing display:%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "669361121": {
-      "message": "Sleep still need to stop %d activities",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "674932310": {
-      "message": "Setting Intent of %s to target %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "675705156": {
-      "message": "resumeTopActivity: Top activity resumed %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "685047360": {
-      "message": "Resizing window %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_RESIZE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "686185515": {
-      "message": "Resize reasons for w=%s:  %s configChanged=%b didFrameInsetsChange=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_RESIZE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "691515534": {
-      "message": "  Commit wallpaper becoming invisible: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "693423992": {
-      "message": "setAnimationLocked: setting mFocusMayChange true",
-      "level": "INFO",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "701366755": {
-      "message": "Attempt to transfer touch gesture with non-existent embedded window",
-      "level": "WARN",
-      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
-      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
-    },
-    "704998117": {
-      "message": "Failed to create surface control for %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "708142634": {
-      "message": "Top resumed state released %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "715749922": {
-      "message": "Allowlisting %d:%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "723575093": {
-      "message": "Attempted to add window with a client %s that is dead. Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "726205185": {
-      "message": "Moving to DESTROYED: %s (destroy skipped)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "733466617": {
-      "message": "Wallpaper token %s visible=%b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/WallpaperWindowToken.java"
-    },
-    "736692676": {
-      "message": "Config is relaunching %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "743418423": {
-      "message": "Sending TaskFragment error exception=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "744171317": {
-      "message": "      SKIP: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "745391677": {
-      "message": "  CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x \/ %s",
-      "level": "INFO",
-      "group": "WM_SHOW_SURFACE_ALLOC",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "765395228": {
-      "message": "onAnimationFinished(): controller=%s reorderMode=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "769218938": {
-      "message": "Loaded animation %s for %s, duration: %d, stack=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "781471998": {
-      "message": "moveWindowTokenToDisplay: Cannot move to the original display for token: %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "782864973": {
-      "message": "Releasing screen wakelock, obscured by %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_KEEP_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "791468751": {
-      "message": "Pausing rotation during re-position",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/TaskPositioner.java"
-    },
-    "793568608": {
-      "message": "        SKIP: sibling is visible but not part of transition",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "794570322": {
-      "message": "Now closing app %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "801521566": {
-      "message": "Content Recording: Attempting to mirror %d from %d but no DisplayContent associated. Changing to mirror default display.",
-      "level": "WARN",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "806891543": {
-      "message": "Setting mOrientationChangeComplete=true because wtoken %s numInteresting=%d numDrawn=%d",
-      "level": "INFO",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "810599500": {
-      "message": "SURFACE isSecure=%b: %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "824532141": {
-      "message": "lastState=%s newState=%s alpha=%f minAlpha=%f fractionRendered=%f minFractionRendered=%f",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "829434921": {
-      "message": "Draw state now committed in %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "835814848": {
-      "message": "%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "851368695": {
-      "message": "Deferred transition id=%d has been continued before the TaskFragmentTransaction=%s is finished",
-      "level": "WARN",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "872933199": {
-      "message": "Changing focus from %s to %s displayId=%d Callers=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "873160948": {
-      "message": "Activity=%s reparent to taskId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "873914452": {
-      "message": "goodToGo()",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "892244061": {
-      "message": "Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d",
-      "level": "INFO",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "895158150": {
-      "message": "allPausedActivitiesComplete: r=%s state=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "898863925": {
-      "message": "Attempted to add QS dialog window with unknown token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "906215061": {
-      "message": "Apply window transaction, syncId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
-    },
-    "913494177": {
-      "message": "removeAllWindowsIfPossible: removing win=%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_WINDOW_MOVEMENT",
-      "at": "com\/android\/server\/wm\/WindowToken.java"
-    },
-    "916191774": {
-      "message": "Orientation change complete in %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "935418348": {
-      "message": "resumeTopActivity: Skip resume: some activity pausing.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "937080808": {
-      "message": "Content Recording: Recorded task is removed, so stop recording on display %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "939638078": {
-      "message": "config_deviceTabletopRotations is not defined. Half-fold letterboxing will work inconsistently.",
-      "level": "WARN",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "948208142": {
-      "message": "Setting Activity.mLauncherTaskBehind to true. Activity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "950074526": {
-      "message": "setLockTaskMode: Can't lock due to auth",
-      "level": "WARN",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "954470154": {
-      "message": "FORCED DISPLAY SCALING DISABLED",
-      "level": "INFO",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "956374481": {
-      "message": "removeLockedTask: task=%s last task, reverting locktask mode. Callers=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "958338552": {
-      "message": "grantEmbeddedWindowFocus win=%s dropped focus so setting focus to null since no candidate was found",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "959486822": {
-      "message": "setSyncGroup #%d on %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "966569777": {
-      "message": "SyncGroup %d: onSurfacePlacement checking %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
-    },
-    "969323241": {
-      "message": "Sending new config to %s, config: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "972354148": {
-      "message": "\tcontainer=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "975028389": {
-      "message": "unable to call receiver for empty keyboard shortcuts",
-      "level": "ERROR",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "975275467": {
-      "message": "Set animatingExit: reason=remove\/isAnimating win=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "979347997": {
-      "message": "Launch on display check: disallow activity embedding without permission.",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "987903142": {
-      "message": "Sleep needs to pause %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "996960396": {
-      "message": "Starting Transition %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "1001904964": {
-      "message": "***** BOOT TIMEOUT: forcing display enabled",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1015746067": {
-      "message": "Display id=%d is ignoring orientation request for %d, return %d following a per-app override for %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "1022095595": {
-      "message": "TaskFragment info changed name=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "1023413388": {
-      "message": "Finish waiting for pause of: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1030898920": {
-      "message": "notifyInsetsControlChanged for %s ",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_INSETS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1033274509": {
-      "message": "moveWindowTokenToDisplay: Attempted to move non-existing token: %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1040675582": {
-      "message": "Can't report activity configuration update - client not running, activityRecord=%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1042363394": {
-      "message": "Attempt to transfer touch gesture using a host window with no input channel",
-      "level": "WARN",
-      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
-      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
-    },
-    "1046228706": {
-      "message": "Defer transition id=%d for TaskFragmentTransaction=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "1046922686": {
-      "message": "requestScrollCapture: caught exception dispatching callback: %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1047505501": {
-      "message": "notifyInsetsChanged for %s ",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_INSETS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1047769218": {
-      "message": "Finishing activity r=%s, result=%d, data=%s, reason=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1049367566": {
-      "message": "Sending to proc %s new config %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/WindowProcessController.java"
-    },
-    "1051545910": {
-      "message": "Exit animation finished in %s: remove=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1068803972": {
-      "message": "Activity paused: token=%s, timeout=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1073230342": {
-      "message": "startAnimation",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
-    },
-    "1075460705": {
-      "message": "Continue transition id=%d for TaskFragmentTransaction=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "1087494661": {
-      "message": "Clear window stuck on animatingExit status: %s",
-      "level": "WARN",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1088929964": {
-      "message": "onLockTaskPackagesUpdated: starting new locktask task=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "1089714158": {
-      "message": "  FREEZE %s: DESTROY",
-      "level": "INFO",
-      "group": "WM_SHOW_SURFACE_ALLOC",
-      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
-    },
-    "1090378847": {
-      "message": "Checking %d windows",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "1100065297": {
-      "message": "Attempted to get IME policy of a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1105210816": {
-      "message": "Skipping config check in destroyed state %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1112047265": {
-      "message": "finishDrawingWindow: %s mDrawState=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1115248873": {
-      "message": "Calling onTransitionReady: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "1115417974": {
-      "message": "FORCED DISPLAY SIZE: %dx%d",
-      "level": "INFO",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1126328412": {
-      "message": "Scheduling idle now: forceIdle=%b immediate=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1140424002": {
-      "message": "Finished screen turning on...",
-      "level": "INFO",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
-    },
-    "1145016093": {
-      "message": "Content Recording: Attempting to mirror self on %d",
-      "level": "WARN",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "1149424314": {
-      "message": "Unregister display organizer=%s uid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
-    },
-    "1151072840": {
-      "message": "collectTaskRemoteAnimations, target: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "1164325516": {
-      "message": "onExitAnimationDone in %s: exiting=%b remove=%b selfAnimating=%b anim=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1166381079": {
-      "message": "Execute app transition: %s, displayId: %d Callers=%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "1175495463": {
-      "message": "ImeContainer just became organized. Reparenting under parent. imeParentSurfaceControl=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "1178653181": {
-      "message": "Old wallpaper still the target.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/WallpaperController.java"
-    },
-    "1191587912": {
-      "message": "Moved rootTask=%s behind rootTask=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "1192413464": {
-      "message": "Comparing existing cls=%s \/aff=%s to new cls=%s \/aff=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "1208313423": {
-      "message": "addWindowToken: Attempted to add token: %s for non-exiting displayId=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1210037962": {
-      "message": "Register remote animations for organizer=%s uid=%d pid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "1219600119": {
-      "message": "addWindow: win=%s Callers=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/WindowToken.java"
-    },
-    "1224184681": {
-      "message": "No longer Stopped: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1224307091": {
-      "message": "checkBootAnimationComplete: Animation complete!",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1239439010": {
-      "message": "moveFocusableActivityToTop: set focused, activity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1251721200": {
-      "message": "unregister failed, couldn't find deathRecipient for %s with id=%d",
-      "level": "ERROR",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "1252594551": {
-      "message": "Window types in WindowContext and LayoutParams.type should match! Type from LayoutParams is %d, but type from WindowContext is %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1254403969": {
-      "message": "Surface returned was null: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1264179654": {
-      "message": "No focused window, defaulting to top current task's window",
-      "level": "WARN",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "1270792394": {
-      "message": "Resumed after relaunch %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1282992082": {
-      "message": "Disabling player for transition #%d because display isn't enabled yet",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "1284122013": {
-      "message": "TaskFragment appeared name=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "1288731814": {
-      "message": "WindowState.hideLw: setting mFocusMayChange true",
-      "level": "INFO",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1288920916": {
-      "message": "Error sending initial insets change to WindowContainer overlay",
-      "level": "ERROR",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "1305412562": {
+    "-4921282642721622589": {
       "message": "Report configuration: %s %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityClientController.java"
     },
-    "1309365288": {
-      "message": "Removing dim surface %s on transaction %s",
+    "-1597980207704427048": {
+      "message": "Frontmost changed immersion: %s",
       "level": "DEBUG",
-      "group": "WM_DEBUG_DIMMER",
-      "at": "com\/android\/server\/wm\/SmoothDimmer.java"
+      "group": "WM_DEBUG_IMMERSIVE",
+      "at": "com\/android\/server\/wm\/ActivityClientController.java"
     },
-    "1316533291": {
-      "message": "State movement: %s from:%s to:%s reason:%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
+    "-6509265758887333864": {
+      "message": "Can't report activity moved to display - client not running, activityRecord=%s, displayId=%d",
+      "level": "WARN",
+      "group": "WM_DEBUG_SWITCH",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1325649102": {
-      "message": "Bad requesting window %s",
+    "-4183059578873561863": {
+      "message": "Reporting activity moved to display, activityRecord=%s, displayId=%d, config=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SWITCH",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "7435279034964784633": {
+      "message": "Can't report activity configuration update - client not running, activityRecord=%s",
       "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1329340614": {
-      "message": "Orientation not waiting for draw in %s, surfaceController %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1330804250": {
-      "message": "addChild: %s at top.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "1331177619": {
-      "message": "Attempted to add a toast window with unknown token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1335791109": {
-      "message": "createSurface %s: mDrawState=DRAW_PENDING",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "1337596507": {
-      "message": "Sending to proc %s new compat %s",
-      "level": "VERBOSE",
       "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/CompatModePackages.java"
-    },
-    "1346895820": {
-      "message": "ScreenRotation still animating: type: %d\nmDisplayAnimator: %s\nmEnterBlackFrameAnimator: %s\nmRotateScreenAnimator: %s\nmScreenshotRotationAnimator: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
-    },
-    "1360176455": {
-      "message": "stopFreezingDisplayLocked: Returning waitingForConfig=%b, waitingForRemoteDisplayChange=%b, mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, mClientFreezingScreen=%b, mOpeningApps.size()=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1364126018": {
-      "message": "Resumed activity; dropping state of: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1364498663": {
-      "message": "notifyAppResumed: wasStopped=%b %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1373000889": {
-      "message": "abortShowImePostLayout",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
-    },
-    "1381227466": {
-      "message": "App is requesting an orientation, return %d for display id=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
-    },
-    "1382634842": {
-      "message": "Unregistering listener=%s with id=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "1393721079": {
-      "message": "Starting remote display change: from [rot = %d], to [%dx%d, rot = %d]",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java"
-    },
-    "1396893178": {
-      "message": "createRootTask unknown displayId=%d",
-      "level": "ERROR",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "1401295262": {
-      "message": "Mode default, asking user",
-      "level": "WARN",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "1401700824": {
-      "message": "Window drawn win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1422781269": {
-      "message": "Resuming rotation after re-position",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/TaskPositioner.java"
-    },
-    "1423418408": {
-      "message": "unable to restore pointer icon",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1430336882": {
-      "message": "findFocusedWindow: focusedApp windows not focusable using new focus @ %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "1434383382": {
-      "message": "Attempted to get flag of a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1445704347": {
-      "message": "coveredRegionsAbove updated with %s frame:%s region:%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "1448683958": {
-      "message": "Override pending remote transitionSet=%b adapter=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "1457990604": {
-      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM_IN_PLACE transit=%s Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "1460759282": {
-      "message": "getAnimationTarget in=%s, out=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "1463355909": {
-      "message": "Queueing legacy sync-set: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "1469310004": {
-      "message": "          SKIP: common mode mismatch. was %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "1473051122": {
-      "message": "Pausing configuration dispatch for  %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1494644409": {
-      "message": "  Rejecting as detached: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "1495525537": {
-      "message": "createWallpaperAnimations()",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "1497304204": {
-      "message": "Deferring rotation, rotation is paused.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "1504168072": {
-      "message": "removeIfPossible: %s callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1511273241": {
-      "message": "Refreshing activity for camera compatibility treatment, activityRecord=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "1518495446": {
-      "message": "removeWindowToken: Attempted to remove non-existing token: %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1519757176": {
-      "message": "setHomeApp(%s)",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "1520642640": {
-      "message": "Attempt to transfer touch gesture using embedded window with no associated host",
-      "level": "WARN",
-      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
-      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
-    },
-    "1521476038": {
-      "message": "Attempted to set flag to a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1524174282": {
-      "message": "Launch on display check: no caller info, skip check",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "1525976603": {
-      "message": "cancelAnimation(): reason=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "1528528509": {
-      "message": "No thumbnail header bitmap for: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1546187372": {
-      "message": "Content Recording: Pause the recording session on display %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
-    },
-    "1557732761": {
-      "message": "For Intent %s bringing to top: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "1563755163": {
-      "message": "Permission Denial: %s from pid=%d, uid=%d requires %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1577579529": {
-      "message": "win=%s destroySurfaces: appStopped=%b win.mWindowRemovalAllowed=%b win.mRemoveOnExit=%b",
-      "level": "ERROR",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1584270979": {
-      "message": "applyAnimation: container=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "1589610525": {
-      "message": "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: anim=%s transit=%s isEntrance=true Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "1610646518": {
-      "message": "Enqueueing pending finish: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1621562070": {
-      "message": "    startWCT=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "1628345525": {
-      "message": "Now opening app %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "1634557978": {
-      "message": "**** Dismissing screen rotation animation",
-      "level": "INFO",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1635062046": {
-      "message": "Skipping config check invisible: %s",
+    "-7418876140361338495": {
+      "message": "Sending new config to %s, config: %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1635462459": {
-      "message": "onMovedByResize: Moving %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RESIZE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1640436199": {
-      "message": "No app is requesting an orientation, return %d for display id=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
-    },
-    "1653025361": {
-      "message": "Register task fragment organizer=%s uid=%d pid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "1653210583": {
-      "message": "Removing app %s delayed=%b animation=%s animating=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
+    "-4284934398288119962": {
+      "message": "Can't report activity position update - client not running, activityRecord=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1658605381": {
-      "message": "onImeControlTargetChanged %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/InsetsStateController.java"
-    },
-    "1661414284": {
-      "message": "Content Recording: Unable to tell MediaProjectionManagerService about resizing the active projection: %s",
-      "level": "ERROR",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "1670933628": {
-      "message": " Setting allReady override",
+    "7244227111034368231": {
+      "message": "Sending position change to %s, onTop: %b",
       "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1674747211": {
-      "message": "%s forcing orientation to %d for display id=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayArea.java"
-    },
-    "1677260366": {
-      "message": "Finish starting %s: first real window is shown, no animation",
+    "338586566486930495": {
+      "message": "Checking theme of starting window: 0x%x",
       "level": "VERBOSE",
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1679569477": {
-      "message": "Configuration doesn't matter not running %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1687944543": {
-      "message": "Content Recording: Unable to update recording for display %d to new bounds %s and\/or orientation %d and\/or surface size %s, since the surface is not available.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "1699269281": {
-      "message": "Don't organize or trigger events for untrusted displayId=%d",
-      "level": "WARN",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
-    },
-    "1712935427": {
-      "message": "Content Recording: Unable to start recording for display %d since the surface is not available.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "1720229827": {
-      "message": "Creating animation bounds layer",
-      "level": "INFO",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1721036256": {
-      "message": "Attempt to transfer touch gesture using embedded window that has no input channel",
-      "level": "WARN",
-      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
-      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
-    },
-    "1730300180": {
-      "message": "PendingStartTransaction found",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
-    },
-    "1735199721": {
-      "message": "Queueing transition: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "1739298851": {
-      "message": "removeWindowToken: Attempted to remove token: %s for non-exiting displayId=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1746778201": {
-      "message": "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1750878635": {
-      "message": "Content Recording: Provided surface for recording on display %d is not present, so do not update the surface",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "1756082882": {
-      "message": "Orientation change skips hidden %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "1774661765": {
-      "message": "Devices still not ready after waiting %d milliseconds before attempting to detect safe mode.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1781673113": {
-      "message": "onAnimationFinished(): targetRootTask=%s targetActivity=%s mRestoreTargetBehindRootTask=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "1786463281": {
-      "message": "Adding trusted state listener=%s with id=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "1789321832": {
-      "message": "Then token:%s is invalid. It might be removed",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1789603530": {
-      "message": "Removing activity %s hasSavedState=%b stateNotNeeded=%s finishing=%b state=%s callers=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1794249572": {
-      "message": "Requesting StartTransition: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "1804245629": {
-      "message": "Attempted to add starting window to token but already cleaned",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1805116444": {
-      "message": "We don't support remote animation for Task with multiple TaskFragmentOrganizers.",
-      "level": "ERROR",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "1810019902": {
-      "message": "TRANSIT_FLAG_OPEN_BEHIND,  adding %s to mOpeningApps",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1810209625": {
-      "message": "Animation done in %s: exiting=%b, reportedVisible=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "1810872941": {
-      "message": "setWallpaperCropHints: non-existent wallpaper token: %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1820873642": {
-      "message": "SyncGroup %d:  Unfinished dependencies: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
-    },
-    "1822314934": {
-      "message": "Expected target rootTask=%s to restored behind rootTask=%s but it is behind rootTask=%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "1822843721": {
-      "message": "Aborted starting %s: startingData=%s",
+    "-2561793317091789573": {
+      "message": "Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1824105730": {
-      "message": "setLockTaskAuth: task=%s mLockTaskAuth=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "1829094918": {
-      "message": "onLockTaskPackagesUpdated: removing %s mLockTaskAuth()=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "1831008694": {
-      "message": "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s surfaceInsets=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "1836214582": {
-      "message": "startingData was nulled out before handling mAddStartingWindow: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1836306327": {
-      "message": "Skipping set freeze of %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1856783490": {
-      "message": "resumeTopActivity: Restarting %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "1865125884": {
-      "message": "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, mScreenOnFully=%b, mKeyguardDrawComplete=%b, mWindowManagerDrawComplete=%b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
-    },
-    "1866772666": {
-      "message": "SAFE MODE not enabled",
-      "level": "INFO",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1874559932": {
-      "message": "The TaskDisplayArea with %s does not exist.",
-      "level": "WARN",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaPolicyBuilder.java"
-    },
-    "1877863087": {
-      "message": "Display id=%d is ignoring orientation request for %d, return %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "1879463933": {
-      "message": "attachWindowContextToWindowToken: calling from non-existing process pid=%d uid=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1891501279": {
-      "message": "cancelAnimation(): reason=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "1912291550": {
-      "message": "Sleep still waiting to pause %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "1918448345": {
-      "message": "Task appeared taskId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "1928325128": {
-      "message": "Run showImeRunner",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
-    },
-    "1931178855": {
-      "message": "\tnonApp=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "1945495497": {
-      "message": "Focused window didn't have a valid surface drawn.",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "1946983717": {
-      "message": "Waiting for screen on due to %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "1947239194": {
-      "message": "Deferring rotation, still finishing previous rotation",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "1947936538": {
-      "message": "Found matching class!",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "1955470028": {
-      "message": "computeFractionRendered: visibleRegion=%s screenBounds=%s contentSize=%s scale=%f,%f",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "1964565370": {
-      "message": "Starting remote animation",
-      "level": "INFO",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "1967975839": {
-      "message": "Changing app %s visible=%b performLayout=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "1984782949": {
-      "message": ">>> OPEN TRANSACTION animate",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowAnimator.java"
-    },
-    "1984843251": {
-      "message": "Hiding wallpaper %s from %s target=%s prev=%s callers=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/WallpaperController.java"
-    },
-    "1995093920": {
-      "message": "Checking to restart %s: changed=0x%s, handles=0x%s, mLastReportedConfiguration=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1999594750": {
-      "message": "startAnimation",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java"
-    },
-    "2001473656": {
-      "message": "App %s is focused, but the window is not ready. Start a transaction to remove focus from the window of non-focused apps.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/InputMonitor.java"
-    },
-    "2004282287": {
-      "message": "Override sync-method for %s because seamless rotating",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "2010476671": {
-      "message": "Animation done in %s: reportedVisible=%b okToDisplay=%b okToAnimate=%b startingDisplayed=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "2018454757": {
-      "message": "WS.removeImmediately: %s Already removed...",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "2018852077": {
+    "7269690012594027154": {
       "message": "Creating SplashScreenStartingData",
       "level": "VERBOSE",
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "2019765997": {
-      "message": "selectRotationAnimation topFullscreen=%s rotationAnimation=%d forceJumpcut=%b",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    "-3432060893368468911": {
+      "message": "Creating SnapshotStartingData",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "2021079047": {
-      "message": "%s",
+    "1789854065584848502": {
+      "message": "startingData was nulled out before handling mAddStartingWindow: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "5659016061937922595": {
+      "message": "Add starting %s: startingData=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-9066702108316454290": {
+      "message": "Aborted starting %s: startingData=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "7506106334102501360": {
+      "message": "Added starting %s: startingWindow=%s startingView=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "1048048288756547220": {
+      "message": "Surface returned was null: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1298801500610545721": {
+      "message": "Cleaning splash screen token=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1948849214526113495": {
+      "message": "Clearing startingData for token=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "5545923784327902026": {
+      "message": "Schedule remove starting %s startingWindow=%s animate=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-5150982660941074218": {
+      "message": "startingWindow was set but startingSurface==null, couldn't remove",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-2178757341169633804": {
+      "message": "Tried to remove starting window but startingWindow was null: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "5521236266092347335": {
+      "message": "reparent: moving activity=%s to new task fragment in task=%d at %d",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-9024836052864189016": {
+      "message": "moveFocusableActivityToTop: unfocusable activity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "134255351804410010": {
+      "message": "moveFocusableActivityToTop: already on top and focused, activity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1058622321669556178": {
+      "message": "moveFocusableActivityToTop: set focused, activity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "731006689098152100": {
+      "message": "moveFocusableActivityToTop: activity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "3707721620395081349": {
+      "message": "Finishing activity r=%s, result=%d, data=%s, reason=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-3691592300155948194": {
+      "message": "Finish needs to pause: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "5813636479397543744": {
+      "message": "Finish waiting for pause of: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-2989211291975863399": {
+      "message": "destroyIfPossible: r=%s destroy returned removed=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_CONTAINERS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "3169053633576517098": {
+      "message": "Enqueueing pending finish: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "9050478058743283018": {
+      "message": "activity %s already destroying, skipping request with reason:%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "5672598223877126839": {
+      "message": "Moving to DESTROYING: %s (destroy requested)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1834399855266808961": {
+      "message": "Moving to DESTROYED: %s (destroy skipped)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "3282063745558462269": {
+      "message": "Moving to DESTROYED: %s (no app)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "8836546031252812807": {
+      "message": "Removing activity %s, reason= %s callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "8348126473928520781": {
+      "message": "Moving to DESTROYED: %s (removed from history)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-8001673213497887656": {
+      "message": "activityDestroyedLocked: r=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_CONTAINERS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "587363723665813898": {
+      "message": "Removing activity %s hasSavedState=%b stateNotNeeded=%s finishing=%b state=%s callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1842512343787359105": {
+      "message": "Removing app token: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "5548174277852675449": {
+      "message": "Removing app %s delayed=%b animation=%s animating=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-601582700132879947": {
+      "message": "removeAppToken: %s delayed=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "3478214322581157355": {
+      "message": "removeAppToken make exiting: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-7226216420432530281": {
+      "message": "Removing focused app token:%s displayId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "8361394136152947990": {
+      "message": "Moving existing starting %s from %s to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-3450064502566932331": {
+      "message": "Removing starting %s from %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "8639603536400037285": {
+      "message": "Moving pending starting from %s to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-3452055378690362514": {
+      "message": "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "1728033820691545386": {
+      "message": "No longer Stopped: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "5062176994575790703": {
+      "message": "TRANSIT_FLAG_OPEN_BEHIND,  adding %s to mOpeningApps",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-477271988506706928": {
+      "message": "commitVisibility: %s: visible=%b visibleRequested=%b, isInTransition=%b, runningAnimation=%b, caller=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-6873410057142191118": {
+      "message": "State movement: %s from:%s to:%s reason:%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "4437231720834282527": {
+      "message": "State unchanged from:%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "926038819327785799": {
+      "message": "notifyAppResumed: wasStopped=%b %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "1734586111478674085": {
+      "message": "Resumed activity; dropping state of: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-69666241054231397": {
+      "message": "Refreshed activity: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "1256300416726217367": {
+      "message": "Activity paused: token=%s, timeout=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "6879640870754727133": {
+      "message": "Moving to PAUSED: %s %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "2737811012914917932": {
+      "message": "Executing finish of failed to pause activity: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-2566496855129705006": {
+      "message": "Waiting for pause to complete...",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "7498807658620137882": {
+      "message": "no-history finish of %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "3207149655622038378": {
+      "message": "Not finishing noHistory %s on stop because we're just sleeping",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-2530718588485487045": {
+      "message": "Moving to STOPPING: %s (stop requested)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-8424334454318351870": {
+      "message": "Stop failed; moving to STOPPED: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-4913512058893421188": {
+      "message": "Saving icicle of %s: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "7613353074402340933": {
+      "message": "Moving to STOPPED: %s (stop complete)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "3981777934616509782": {
+      "message": "Scheduling idle now: forceIdle=%b immediate=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "1083992181663415298": {
+      "message": "Skipping set freeze of %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "3713860954819212080": {
+      "message": "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "7696002120820208745": {
+      "message": "Clear freezing of %s force=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-8387262166329116492": {
+      "message": "No longer freezing: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-6965298896142649709": {
+      "message": "Finish starting %s: first real window is shown, no animation",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "3235691043029201724": {
+      "message": "Setting mOrientationChangeComplete=true because wtoken %s numInteresting=%d numDrawn=%d",
+      "level": "INFO",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "5991628884266137609": {
+      "message": "Creating animation bounds layer",
+      "level": "INFO",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1836789237982086339": {
+      "message": "No thumbnail header bitmap for: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-8809523216004991008": {
+      "message": "Animation done in %s: reportedVisible=%b okToDisplay=%b okToAnimate=%b startingDisplayed=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-9178011226407552682": {
+      "message": "Setting requested orientation %s for %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1963190756391505590": {
+      "message": "Sandbox max bounds for uid %s to bounds %s. config to never sandbox = %s, config to always sandbox = %s, letterboxing from mismatch with parent bounds = %s, has mCompatDisplayInsets = %s, should create compatDisplayInsets = %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "2612201759169917322": {
+      "message": "Pausing configuration dispatch for  %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "2022422429": {
-      "message": "createAnimationAdapter(): container=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "2024493888": {
-      "message": "\tWallpaper of display=%s is not visible",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
-    },
-    "2028163120": {
-      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s isEntrance=%s Callers=%s",
+    "5153784493059555057": {
+      "message": "Resuming configuration dispatch for %s",
       "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "2034780299": {
-      "message": "CHECK_IF_BOOT_ANIMATION_FINISHED:",
+    "-8630021188868292872": {
+      "message": "Skipping config check (will change): %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-3976984054291875926": {
+      "message": "Configuration doesn't matter in finishing %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1036762753077003128": {
+      "message": "Skipping config check in destroyed state %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-6543078196636665108": {
+      "message": "Skipping config check invisible: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-3588725633248053181": {
+      "message": "Ensuring correct configuration: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "4672360193194734037": {
+      "message": "Configuration & display unchanged in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-8624278141553396410": {
+      "message": "Skipping config check for initializing activity: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "2485365009287691179": {
+      "message": "Configuration no differences in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-8909639363543223474": {
+      "message": "Configuration changes for %s, allChanges=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-8048404379899908050": {
+      "message": "Configuration doesn't matter not running %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "4979286847769557939": {
+      "message": "Checking to restart %s: changed=0x%s, handles=0x%s, mLastReportedConfiguration=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "6779426581354721909": {
+      "message": "Config is relaunching %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "8969401915706456725": {
+      "message": "Config is relaunching invisible activity %s called by %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "328802837600679598": {
+      "message": "Moving to %s Relaunching %s callers=%s",
       "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "2039056415": {
-      "message": "Found matching affinity candidate!",
+    "-3997125892953197985": {
+      "message": "Resumed after relaunch %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "1665699123574159131": {
+      "message": "Starting activity when config will change = %b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityStarter.java"
+    },
+    "4748139468532105082": {
+      "message": "Updating to new configuration after starting activity.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityStarter.java"
+    },
+    "-2867366986304729": {
+      "message": "Bring to front target: %s from %s",
       "level": "DEBUG",
       "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+      "at": "com\/android\/server\/wm\/ActivityStarter.java"
     },
-    "2043434284": {
-      "message": "setWallpaperShowWhenLocked: non-existent wallpaper token: %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "2045641491": {
-      "message": "Checking %d opening apps (frozen=%b timeout=%b)...",
+    "-2190454940975874759": {
+      "message": "Starting new activity %s in new task %s",
       "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityStarter.java"
     },
-    "2053743391": {
-      "message": " Add condition %s for #%d",
+    "5445799252721678675": {
+      "message": "Initial config: %s",
       "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
-    "2060978050": {
-      "message": "moveWindowTokenToDisplay: Attempted to move token: %s to non-exiting displayId=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "2066210760": {
-      "message": "foldStateChanged: displayId %d, halfFoldStateChanged %s, saved rotation: %d, mUserRotation: %d, mLastSensorRotation: %d, mLastOrientation: %d, mRotation: %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "2070726247": {
-      "message": "InsetsSource updateVisibility for %s, serverVisible: %s clientVisible: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_INSETS",
-      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
-    },
-    "2075693141": {
-      "message": "Set animatingExit: reason=startExitingAnimation\/%s win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "2079410261": {
-      "message": "applyAnimation:  override requested, but it is prohibited by policy.",
+    "-3811526397232923712": {
+      "message": "Cannot launch dream activity due to invalid state. dream component: %s packageName: %s",
       "level": "ERROR",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
+      "group": "WM_DEBUG_DREAM",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
-    "2083556954": {
-      "message": "Set mOrientationChanging of %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    "-6981899770129924827": {
+      "message": "Dream packageName does not match active dream. Package %s does not match %s",
+      "level": "ERROR",
+      "group": "WM_DEBUG_DREAM",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
-    "2086878461": {
-      "message": "Could not send command %s with parameters %s. %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "2100457473": {
-      "message": "Task=%d contains embedded TaskFragment. Disabled all input during TaskFragment remote animation.",
+    "6075150529915862250": {
+      "message": "Applying new update lock state '%s' for %s",
       "level": "DEBUG",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+      "group": "WM_DEBUG_IMMERSIVE",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
-    "2117696413": {
+    "-4356952232698761083": {
+      "message": "setFocusedRootTask: taskId=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "301842347780487555": {
+      "message": "setFocusedTask: taskId=%d touchedActivity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "7095858131234795548": {
       "message": "moveTaskToFront: moving taskId=%d",
       "level": "DEBUG",
       "group": "WM_DEBUG_TASKS",
       "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
-    "2119122320": {
+    "-4458288191054594222": {
+      "message": "Could not find task for id: %d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "-1136891560663761442": {
+      "message": "moveTaskToRootTask: moving task=%d to rootTaskId=%d toTop=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "6954122272402912822": {
+      "message": "startLockTaskMode: %s",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "-829638795650515884": {
+      "message": "Allowlisting %d:%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "893763316922465955": {
+      "message": "moveRootTaskToDisplay: moving taskId=%d to displayId=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "8392804603924461448": {
+      "message": "%s: caller %d is using old GET_TASKS but privileged; allowing",
+      "level": "WARN",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "4303745325174700522": {
+      "message": "%s: caller %d does not hold REAL_GET_TASKS; limiting output",
+      "level": "WARN",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "-559595900417262876": {
+      "message": "Allowing features %d:0x%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "2008996027621913637": {
+      "message": "Updating global configuration to: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "-6404059840638143757": {
+      "message": "Update process config of %s to new config %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "2959074735946674755": {
+      "message": "Trying to update display configuration for system\/invalid process.",
+      "level": "WARN",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "5668810920995272206": {
+      "message": "Trying to update display configuration for invalid process, pid=%d",
+      "level": "WARN",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "-1123414663662718691": {
+      "message": "setVr2dDisplayId called for: %d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "7803197981786977817": {
+      "message": "no-history finish of %s on new resume",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "4094852138446437211": {
+      "message": "realStartActivityLocked: Skipping start of r=%s some activities pausing...",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "1045761390992110034": {
+      "message": "Moving to PAUSED: %s (starting in paused state)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "-8529426827020190143": {
+      "message": "Launch on display check: displayId=%d callingPid=%d callingUid=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "9147909968067116569": {
+      "message": "Launch on display check: no caller info, skip check",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "4781135167649953680": {
+      "message": "Launch on display check: allow launch any on display",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "7828411869729995271": {
+      "message": "Launch on display check: disallow launch on virtual display for not-embedded activity.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "-2215878620906309682": {
+      "message": "Launch on display check: disallow activity embedding without permission.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "986565579776405555": {
+      "message": "Launch on display check: %s launch for userId=%d on displayId=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "-2201418325681949201": {
+      "message": "Launch on display check: allow launch for owner of the display",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "-4258279435559028377": {
+      "message": "Launch on display check: allow launch for caller present on the display",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "1496536241884839051": {
+      "message": "Stopping %s: nowVisible=%b animating=%b finishing=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "5677125188685281770": {
+      "message": "Ready to stop: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "3604633008357193496": {
+      "message": "Waiting for top state to be released by %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "3997062844427155487": {
+      "message": "Top resumed state released %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "-4049608245387511746": {
+      "message": "applyAnimation:  override requested, but it is prohibited by policy.",
+      "level": "ERROR",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "-2133100418670643322": {
+      "message": "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "6121116119545820299": {
+      "message": "applyAnimation: anim=%s transit=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "-8382864384468306610": {
+      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s isEntrance=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "222576013987954454": {
+      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM_IN_PLACE transit=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "4808089291562562413": {
+      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL transit=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "-1463563572526433695": {
+      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s isEntrance=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "-8749850292010208926": {
+      "message": "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "5939232373291430513": {
+      "message": "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: anim=%s transit=%s isEntrance=true Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "9082776604722675018": {
+      "message": "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "-1218632020771063497": {
+      "message": "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b  canCustomizeAppTransition=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "6217525691846442213": {
+      "message": "Override pending remote transitionSet=%b adapter=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "5233255302148535928": {
+      "message": "*** APP TRANSITION TIMEOUT. displayId=%d isTransitionSet()=%b mOpeningApps.size()=%d mClosingApps.size()=%d mChangingApps.size()=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "-5726018006883159788": {
+      "message": "Delaying app transition for recents animation to finish",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "6514556033257323299": {
+      "message": "**** GOOD TO GO",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "3518082157667760495": {
+      "message": "handleAppTransitionReady: displayId=%d appTransition={%s} openingApps=[%s] closingApps=[%s] transit=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "-2503124388387340567": {
+      "message": "Wallpaper animation!",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "855146509305002043": {
+      "message": "We don't support remote animation for Task with multiple TaskFragmentOrganizers.",
+      "level": "ERROR",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "59396412370137517": {
+      "message": "Override with TaskFragment remote animation for transit=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "2280055488397326910": {
+      "message": "Task=%d contains embedded TaskFragment. Disabled all input during TaskFragment remote animation.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "-3156084190956669377": {
+      "message": "Changing app %s visible=%b performLayout=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "-8226278785414579647": {
+      "message": "getAnimationTarget in=%s, out=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "4418653408751596915": {
+      "message": "Now opening app %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "-8367738619313176909": {
+      "message": "Now closing app %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "1855459282905873641": {
+      "message": "Now changing app %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "2951634988136738868": {
+      "message": "Checking %d opening apps (frozen=%b timeout=%b)...",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "4963754906024950916": {
+      "message": "Delaying app transition for screen rotation animation to finish",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "5073676463280304697": {
+      "message": "Check opening app=%s: allDrawn=%b startingDisplayed=%b startingMoved=%b isRelaunching()=%b startingWindow=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "3437142041296647115": {
+      "message": "isFetchingAppTransitionSpecs=true",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "1461079689316480707": {
+      "message": "unknownApps is not empty: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "3579533288018884842": {
+      "message": "Organized TaskFragment is not ready= %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "495867940519492701": {
+      "message": "SyncGroup %d: onSurfacePlacement checking %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
+    "8452501904614439940": {
+      "message": "SyncGroup %d:  Unfinished dependencies: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
+    "616739530932040800": {
+      "message": "SyncGroup %d:  Unfinished container: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
+    "6649777898123506907": {
+      "message": "SyncGroup %d: Finished!",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
+    "4174320302463990554": {
+      "message": "PendingStartTransaction found",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
+    "6310906192788668020": {
+      "message": "SyncGroup %d: Set ready %b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
+    "-476337038362199951": {
+      "message": "SyncGroup %d: Adding to group: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
+    "-2978812352001196863": {
+      "message": "SyncGroup %d: Started %sfor listener: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
+    "-699215053676660941": {
+      "message": "No focused window, defaulting to top current task's window",
+      "level": "WARN",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "-1459414342866553129": {
+      "message": "Current focused window being animated by recents. Overriding back callback to recents controller callback.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "2881085074175114605": {
+      "message": "Focused window didn't have a valid surface drawn.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "-6183551796617134986": {
+      "message": "Focus window is closing.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "4039315468791789889": {
+      "message": "startBackNavigation currentTask=%s, topRunningActivity=%s, callbackInfo=%s, currentFocus=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "8456834061534378653": {
+      "message": "Previous Destination is Activity:%s Task:%s removedContainer:%s, backType=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "4900967164780429209": {
+      "message": "Pending back animation due to another animation is running",
+      "level": "WARN",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "-6431452312492819825": {
+      "message": "onTransactionReady, opening: %s, closing: %s, animating: %s, match: %b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "-4051770154814262074": {
+      "message": "Handling the deferred animation after transition finished",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "2077221835543623088": {
+      "message": "Setting Activity.mLauncherTaskBehind to true. Activity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "-4442170697458371588": {
+      "message": "Setting Activity.mLauncherTaskBehind to false. Activity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "267946503010201613": {
+      "message": "onBackNavigationDone backType=%s, triggerBack=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "-2963535976860666511": {
+      "message": "  BLACK %s: CREATE layer=%d",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/BlackFrame.java"
+    },
+    "-5633771912572750947": {
+      "message": "  BLACK %s: DESTROY",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/BlackFrame.java"
+    },
+    "-74949168947384056": {
+      "message": "Sending to proc %s new compat %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/CompatModePackages.java"
+    },
+    "-6620483833570774987": {
+      "message": "Content Recording: Unexpectedly null window container; unable to update recording for display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "7226080178642957768": {
+      "message": "Content Recording: Display %d was already recording, but pause capture since the task is in PIP",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "-311001578548807570": {
+      "message": "Content Recording: Display %d was already recording, so apply transformations if necessary",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "2350883351096538149": {
+      "message": "Content Recording: Going ahead with updating recording for display %d to new bounds %s and\/or orientation %d and\/or surface size %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "8446758574558556540": {
+      "message": "Content Recording: Unable to update recording for display %d to new bounds %s and\/or orientation %d and\/or surface size %s, since the surface is not available.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "-4320004054011530388": {
+      "message": "Content Recording: Display %d has content (%b) so pause recording",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "5951434375221687741": {
+      "message": "Content Recording: Stop MediaProjection on virtual display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "-3395581813971405090": {
+      "message": "Content Recording: waiting to record, so do nothing",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "6779858226066635065": {
+      "message": "Content Recording: Display %d should start recording, but don't yet since the task is in PIP",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "7051210836345306671": {
+      "message": "Content Recording: Unable to start recording for display %d since the surface is not available.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "2255758299558330282": {
+      "message": "Content Recording: Display %d has no content and is on, so start recording for state %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "2269158922723670768": {
+      "message": "Unable to retrieve window container to start recording for display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "-2177493963028285555": {
+      "message": "Content Recording: Unable to start recording due to null token for display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "-928577038848872043": {
+      "message": "Content Recording: Unable to retrieve task to start recording for display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "-3564317873468917405": {
+      "message": "Content Recording: Unable to start recording due to invalid region for display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "1100676037289065396": {
+      "message": "Content Recording: Apply transformations of shift %d x %d, scale %f x %f, crop (aka recorded content size) %d x %d for display %d; display has size %d x %d; surface has size %d x %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "2330946591287751995": {
+      "message": "Content Recording: Provided surface for recording on display %d is not present, so do not update the surface",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "7993045936648632984": {
+      "message": "Content Recording: Recorded task is removed, so stop recording on display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "3197882223327917085": {
+      "message": "Content Recording: stopping active projection for display %d",
+      "level": "ERROR",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "4391984931064789228": {
+      "message": "Content Recording: Unable to tell MediaProjectionManagerService to stop the active projection for display %d: %s",
+      "level": "ERROR",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "6721270269112237694": {
+      "message": "Content Recording: Unable to tell MediaProjectionManagerService about resizing the active projection: %s",
+      "level": "ERROR",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "1600318776990120244": {
+      "message": "Content Recording: Unable to tell MediaProjectionManagerService about visibility change on the active projection: %s",
+      "level": "ERROR",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "-1451477179301743956": {
+      "message": "Content Recording: Unable to tell log windowing mode change: %s",
+      "level": "ERROR",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "-225319884529912382": {
+      "message": "Content Recording: Accept session updating same display %d with granted consent, with an existing session %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
+    },
+    "-5981322449150461244": {
+      "message": "Content Recording: Ignoring session on same display %d, with an existing session %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
+    },
+    "4226710957373144819": {
+      "message": "Content Recording: Handle incoming session on display %d, with a pre-existing session %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
+    },
+    "-1415855962859555663": {
+      "message": "Content Recording: Incoming session on display %d can't be set since it is already null; the corresponding VirtualDisplay must have already been removed.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
+    },
+    "-5750232782380780139": {
+      "message": "Content Recording: Pause the recording session on display %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
+    },
+    "-8058211784911995417": {
+      "message": "DeferredDisplayUpdater: applying DisplayInfo immediately",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java"
+    },
+    "1944392458089872195": {
+      "message": "DeferredDisplayUpdater: partially applying DisplayInfo immediately",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java"
+    },
+    "8391643185322408089": {
+      "message": "DeferredDisplayUpdater: deferring DisplayInfo update",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java"
+    },
+    "-915675022936690176": {
+      "message": "DeferredDisplayUpdater: applied DisplayInfo after deferring",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java"
+    },
+    "3778139410556664218": {
+      "message": "%s skipping animation and directly setting alpha=%f, blur=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_DIMMER",
+      "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java"
+    },
+    "-6357087772993832060": {
+      "message": "Starting animation on %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_DIMMER",
+      "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java"
+    },
+    "-1187783168730646350": {
+      "message": "Dim animation requested: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_DIMMER",
+      "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java"
+    },
+    "2230151187668089583": {
+      "message": "%s forcing orientation to %d for display id=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayArea.java"
+    },
+    "3968604152682328317": {
+      "message": "Register display organizer=%s uid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
+    "-3066370283926570943": {
+      "message": "Don't organize or trigger events for untrusted displayId=%d",
+      "level": "WARN",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
+    "-943497726140336963": {
+      "message": "Unregister display organizer=%s uid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
+    "5147103403966149923": {
+      "message": "Create TaskDisplayArea uid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
+    "-1659480097203667175": {
+      "message": "Delete TaskDisplayArea uid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
+    "-4514772405648277945": {
+      "message": "DisplayArea appeared name=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
+    "995846188225477231": {
+      "message": "DisplayArea vanished name=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
+    "-1007032390526684388": {
+      "message": "DisplayArea info changed name=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
+    "4917824058925068521": {
+      "message": "The TaskDisplayArea with %s does not exist.",
+      "level": "WARN",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaPolicyBuilder.java"
+    },
+    "1432179297701477868": {
+      "message": "Looking for focus: %s, flags=%d, canReceive=%b, reason=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-1998969924927409574": {
+      "message": "findFocusedWindow: focusedApp=null using new focus @ %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-1513212297283619351": {
+      "message": "findFocusedWindow: focusedApp windows not focusable using new focus @ %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "271075236829935631": {
+      "message": "findFocusedWindow: Reached focused app=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "3066566560703920191": {
+      "message": "findFocusedWindow: Found new focus @ %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-8667452489821572603": {
+      "message": "First draw done in potential wallpaper target %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "6283995720623600346": {
+      "message": "handleNotObscuredLocked: %s was holding screen wakelock but no longer has FLAG_KEEP_SCREEN_ON!!! called by%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "1959209522588955826": {
+      "message": "Acquiring screen wakelock due to %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "352937214222086717": {
+      "message": "Releasing screen wakelock, obscured by %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "2632363530212357762": {
+      "message": "Set mOrientationChanging of %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-9191821315942566105": {
+      "message": "Display id=%d is frozen while keyguard locked, return %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-74384795669614579": {
+      "message": "Display id=%d is ignoring orientation request for %d, return %d following a per-app override for %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-3395592185328682328": {
+      "message": "Display id=%d is ignoring orientation request for %d, return %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "3438870491084701232": {
+      "message": "No app or window is requesting an orientation, return %d for display id=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-1123818872155982592": {
+      "message": "findFocusedWindow: No focusable windows, display=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-2192125645150932161": {
+      "message": "Current transition prevents automatic focus change",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "3101160328044493048": {
+      "message": "Changing focus from %s to %s displayId=%d Callers=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "7634130879993688940": {
+      "message": "setFocusedApp %s displayId=%d Callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-4130402450005935184": {
+      "message": "SURFACE LEAK DESTROY: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "4464269036743635127": {
       "message": "setInputMethodTarget %s",
       "level": "INFO",
       "group": "WM_DEBUG_IME",
       "at": "com\/android\/server\/wm\/DisplayContent.java"
     },
-    "2124732293": {
+    "4835192778854186097": {
+      "message": "create IME snapshot for %s, buff width=%s, height=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "2408509162360028352": {
+      "message": "Set IME snapshot position: (%d, %d)",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "2005731931732324688": {
+      "message": "remove IME snapshot, caller=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-6495118720675662641": {
+      "message": "show IME snapshot, ime target=%s, callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-4354595179162289537": {
+      "message": "setInputMethodInputTarget %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "2432701541536053712": {
+      "message": "DisplayContent: boot is waiting for window of type %d to be drawn",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "5683557566110711213": {
+      "message": "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b wallEnabled=%b haveKeyguard=%b",
+      "level": "INFO",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-124113386733162358": {
+      "message": "onWindowAnimationFinished, wc=%s, type=%s, imeSnapshot=%s, target=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-1556099709547629010": {
+      "message": "ImeContainer just became organized. Reparenting under parent. imeParentSurfaceControl=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "1119786654111970652": {
+      "message": "ImeContainer just became organized but it doesn't have a parent or the parent doesn't have a surface control. mSurfaceControl=%s imeParentSurfaceControl=%s",
+      "level": "ERROR",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "7019634211809476510": {
+      "message": "Execute app transition: %s, displayId: %d Callers=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-3219913508985161450": {
+      "message": "Wallpaper layer changed: assigning layers + relayout",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-8165317816061445169": {
+      "message": "Content Recording: Display %d state was (%d), is now (%d), so update recording?",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "4162342172327950908": {
+      "message": "Content Recording: Attempting to mirror self on %d",
+      "level": "WARN",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "5489691866309868814": {
+      "message": "Content Recording: Found no matching mirror display for id=%d for DEFAULT_DISPLAY. Nothing to mirror.",
+      "level": "WARN",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-39794010824230928": {
+      "message": "Content Recording: Attempting to mirror %d from %d but no DisplayContent associated. Changing to mirror default display.",
+      "level": "WARN",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "6545352723229848841": {
+      "message": "Content Recording: Successfully created a ContentRecordingSession for displayId=%d to mirror content from displayId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-6228339285356824882": {
+      "message": "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, mScreenOnFully=%b, mKeyguardDrawComplete=%b, mWindowManagerDrawComplete=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
+    },
+    "-6028033043540330282": {
+      "message": "Finished screen turning on...",
+      "level": "INFO",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
+    },
+    "-7427596081878257508": {
+      "message": "selectAnimation in %s: transit=%d",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
+    },
+    "-6269658847003264525": {
+      "message": "**** STARTING EXIT",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
+    },
+    "-6776561147903919733": {
+      "message": "Deferring rotation, rotation is paused.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "7439675997626642740": {
+      "message": "Deferring rotation, animation in progress.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "1104181226551849840": {
+      "message": "Deferring rotation, still finishing previous rotation",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-2222079183499215612": {
+      "message": "Deferring rotation, display is not enabled.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "662988298513100908": {
+      "message": "Reverting orientation. Rotating to %s from %s rather than %s.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-7113483678655694375": {
+      "message": "Computed rotation=%s (%d) for display id=%d based on lastOrientation=%s (%d) and oldRotation=%s (%d)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-8809129029906317617": {
+      "message": "Display id=%d selected orientation %s (%d), got rotation %s (%d)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "6753221849083491323": {
+      "message": "Display id=%d rotation changed to %d from %d, lastOrientation=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-1216224951455892544": {
+      "message": "Performing post-rotate rotation after seamless rotation",
+      "level": "INFO",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-7672508047849737424": {
+      "message": "selectRotationAnimation topFullscreen=%s rotationAnimation=%d forceJumpcut=%b",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-2426404033822048710": {
+      "message": "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, orientationSensorEnabled=%b, keyguardDrawComplete=%b, windowManagerDrawComplete=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "7339471241580327852": {
+      "message": "rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "5325136615007859122": {
+      "message": "Invalid surface rotation angle in config_deviceTabletopRotations: %d",
+      "level": "ERROR",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "4616480353797749295": {
+      "message": "config_deviceTabletopRotations is not defined. Half-fold letterboxing will work inconsistently.",
+      "level": "WARN",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "8852346340572084230": {
+      "message": "foldStateChanged: displayId %d, halfFoldStateChanged %s, saved rotation: %d, mUserRotation: %d, mLastSensorRotation: %d, mLastOrientation: %d, mRotation: %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-8674269704471038429": {
+      "message": "onProposedRotationChanged, rotation=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "418312772547457152": {
+      "message": "Enabling listeners",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "4641814558273780952": {
+      "message": "Disabling listeners",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "7429138692709430028": {
+      "message": "Display id=%d is ignoring all orientation requests, camera is active and the top activity is eligible for force rotation, return %s,portrait activity: %b, is natural orientation portrait: %b.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "-7756685416834187936": {
+      "message": "Refreshing activity for camera compatibility treatment, activityRecord=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "-5176775281239247368": {
+      "message": "Reverting orientation after camera compat force rotation",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "-2188976047008497712": {
+      "message": "Saving original orientation before camera compat, last orientation is %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "-8302211458579221117": {
+      "message": "Display id=%d is notified that Camera %s is open for package %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "-1534784331886673955": {
+      "message": "DisplayRotationCompatPolicy: Multi-window toast not shown as package '%s' cannot be found.",
+      "level": "ERROR",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "1797195804376906831": {
+      "message": "Display id=%d is notified that Camera %s is closed, scheduling rotation update.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "-8746776274432739264": {
+      "message": "Display id=%d is notified that Camera %s is closed but activity is still refreshing. Rescheduling an update.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "3622181214422515679": {
+      "message": "Display id=%d is notified that Camera %s is closed, updating rotation.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "-6949326633913532620": {
+      "message": "NOSENSOR override detected",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java"
+    },
+    "-2060428960792625366": {
+      "message": "NOSENSOR override is absent: reverting",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java"
+    },
+    "-4296736202875980050": {
+      "message": "Other orientation overrides are in place: not reverting",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java"
+    },
+    "7928129513685401229": {
+      "message": "Pausing rotation during drag",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DragState.java"
+    },
+    "8231481023986546563": {
+      "message": "Resuming rotation after drag",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DragState.java"
+    },
+    "12662399232325663": {
+      "message": "DRAG %s: pos=(%d,%d)",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/DragState.java"
+    },
+    "-1797662102094201628": {
+      "message": "Attempt to transfer touch gesture with non-existent embedded window",
+      "level": "WARN",
+      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
+      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
+    },
+    "929964979835124721": {
+      "message": "Attempt to transfer touch gesture using embedded window with no associated host",
+      "level": "WARN",
+      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
+      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
+    },
+    "676191989331669410": {
+      "message": "Attempt to transfer touch gesture with host window not associated with embedded window",
+      "level": "WARN",
+      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
+      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
+    },
+    "553249487221306249": {
+      "message": "Attempt to transfer touch gesture using embedded window that has no input channel",
+      "level": "WARN",
+      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
+      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
+    },
+    "-8678904073078032058": {
+      "message": "Attempt to transfer touch gesture using a host window with no input channel",
+      "level": "WARN",
+      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
+      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
+    },
+    "-786355099910065121": {
+      "message": "IME target changed within ActivityRecord",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
+    },
+    "2634707843050913730": {
+      "message": "Schedule IME show for %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
+    },
+    "8923821958256605927": {
+      "message": "Run showImeRunner",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
+    },
+    "-3529253275087521638": {
+      "message": "call showInsets(ime) on %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
+    },
+    "7927729210300708186": {
+      "message": "showInsets(ime) was requested by different window: %s ",
+      "level": "WARN",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
+    },
+    "-6529782994356455131": {
+      "message": "abortShowImePostLayout",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
+    },
+    "-6629998049460863403": {
+      "message": "dcTarget: %s mImeRequester: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
+    },
+    "-8553129529717081823": {
+      "message": "Input focus has changed to %s display=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/InputMonitor.java"
+    },
+    "4027486077547983902": {
+      "message": "App %s is focused, but the window is not ready. Start a transaction to remove focus from the window of non-focused apps.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/InputMonitor.java"
+    },
+    "-8537908614386667236": {
+      "message": "Focus not requested for window=%s because it has no surface or is not focusable.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/InputMonitor.java"
+    },
+    "-6346673514571615151": {
+      "message": "Focus requested for window=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/InputMonitor.java"
+    },
+    "1522894362518893789": {
+      "message": "InsetsSource setWin %s for type %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+    },
+    "6243049416211184258": {
+      "message": "InsetsSource Control %s for target %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+    },
+    "-8234068212532234206": {
+      "message": "InsetsSource updateVisibility for %s, serverVisible: %s clientVisible: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+    },
+    "-8601070090234611338": {
+      "message": "ControlAdapter startAnimation mSource: %s controlTarget: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+    },
+    "-6857870589074001153": {
+      "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+    },
+    "-6684172224226118673": {
+      "message": "onImeControlTargetChanged %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/InsetsStateController.java"
+    },
+    "8891808212671675155": {
+      "message": "clearLockedTasks: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "8970634498594714645": {
+      "message": "removeLockedTask: removed %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "8735562128135241598": {
+      "message": "removeLockedTask: task=%s last task, reverting locktask mode. Callers=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "737192738184050156": {
+      "message": "startLockTaskMode: Can't lock due to auth",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "-7119521978513736788": {
+      "message": "Mode default, asking user",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "-1557441750657584614": {
+      "message": "%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "-4314079913933391851": {
+      "message": "setLockTaskMode: Can't lock due to auth",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "3321878763832425380": {
+      "message": "setLockTaskMode: Locking to %s Callers=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "-4819015209006579825": {
+      "message": "onLockTaskPackagesUpdated: removing %s mLockTaskAuth()=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "2119751067469297845": {
+      "message": "onLockTaskPackagesUpdated: starting new locktask task=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "3788905348567806832": {
+      "message": "startAnimation",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java"
+    },
+    "705955074330737483": {
+      "message": "onAnimationCancelled",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java"
+    },
+    "5106303602270682056": {
+      "message": "Adding display switch to existing collecting transition",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/PhysicalDisplaySwitchTransitionLauncher.java"
+    },
+    "3308140128142966415": {
+      "message": "remove RecentTask %s when finishing user %d",
+      "level": "INFO",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RecentTasks.java"
+    },
+    "-3758280623533049031": {
+      "message": "Preload recents with %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-3365656764099317101": {
+      "message": "Updated config=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-7165162073742035900": {
+      "message": "Real start recents",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-3403665718306852375": {
+      "message": "startRecentsActivity(): intent=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-8325607672707336373": {
+      "message": "No root task above target root task=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-7278356485797757819": {
+      "message": "Moved rootTask=%s behind rootTask=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "1012359606301505741": {
+      "message": "Started intent=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "5474198007669537235": {
+      "message": "onAnimationFinished(): controller=%s reorderMode=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "3525834288436624965": {
+      "message": "onAnimationFinished(): targetRootTask=%s targetActivity=%s mRestoreTargetBehindRootTask=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-5961176083217302671": {
+      "message": "Expected target rootTask=%s to be top most but found rootTask=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-5893976429537642045": {
+      "message": "Expected target rootTask=%s to restored behind rootTask=%s but it is behind rootTask=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "4515487264815398694": {
+      "message": "onRootTaskOrderChanged(): rootTask=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "6530904107141905844": {
+      "message": "screenshotTask(%d): mCanceled=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-3286551982713129633": {
+      "message": "setFinishTaskTransaction(%d): transaction=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "5187133389446459984": {
+      "message": "finish(%b): mCanceled=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "6879496555046975661": {
+      "message": "setInputConsumerEnabled(%s): mCanceled=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-5305978958548091997": {
+      "message": "setHomeApp(%s)",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-3801497203749932106": {
+      "message": "addAnimation(%s)",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "3721473589747203697": {
+      "message": "removeAnimation(%d)",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "5156407755139006078": {
+      "message": "removeWallpaperAnimation()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-1997836523186474317": {
+      "message": "startAnimation(): mPendingStart=%b mCanceled=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-7532294363367395195": {
+      "message": "startAnimation(): Notify animation start: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-1336603089105439710": {
+      "message": "collectTaskRemoteAnimations, target: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "2547528895718568379": {
+      "message": "createWallpaperAnimations()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "5444932814080651576": {
+      "message": "cancelAnimation(): reason=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "622027757443954945": {
+      "message": "cleanupAnimation(): Notify animation finished mPendingAnimations=%d reorderMode=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-5444412205083968021": {
+      "message": "createAnimationAdapter(): container=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "6986037643494242400": {
+      "message": "goodToGo()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-1902984034737899928": {
+      "message": "goodToGo(): Animation canceled already",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "6727618365838540075": {
+      "message": "goodToGo(): No apps to animate, mPendingAnimations=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-2525509826755873433": {
+      "message": "goodToGo(): onAnimationStart, transit=%s, apps=%d, wallpapers=%d, nonApps=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-1148281153370899511": {
+      "message": "startAnimation(): Notify animation start:",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "7501495587927045391": {
+      "message": "cancelAnimation(): reason=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-1424368765415574722": {
+      "message": "Starting remote animation",
+      "level": "INFO",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-2676700429940607853": {
+      "message": "%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "7094394833775573933": {
+      "message": "createAppAnimations()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-4411070227420990074": {
+      "message": "\tAdd container=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-4411631520586057580": {
+      "message": "\tRemove container=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-7002230949892506736": {
+      "message": "createWallpaperAnimations()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "8743612568733301175": {
+      "message": "createNonAppWindowAnimations()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-2716313493239418198": {
+      "message": "onAnimationFinished(): mPendingAnimations=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "7221400292415257709": {
+      "message": "onAnimationFinished(): Notify animation finished:",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "7483194715776694698": {
+      "message": "\tcontainer=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "6697982664439247822": {
+      "message": "\twallpaper=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "6938838346517131964": {
+      "message": "\tnonApp=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-3880290251819699866": {
+      "message": "Finishing remote animation",
+      "level": "INFO",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-7169244688499657832": {
+      "message": "app-onAnimationFinished(): mOuter=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "3923111589554171989": {
+      "message": "app-release(): mOuter=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "8918152561092803537": {
+      "message": "startAnimation",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "1736084564226683342": {
+      "message": "Starting remote display change: from [rot = %d], to [%dx%d, rot = %d]",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java"
+    },
+    "-4617490621756721600": {
+      "message": "resetTaskIntendedTask: calling finishActivity on %s",
+      "level": "WARN",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
+    },
+    "3361857745281957526": {
+      "message": "Removing activity %s from task=%s adding to task=%s Callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
+    },
+    "3958829063955690349": {
+      "message": "Pushing next activity %s out to target's task %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
+    },
+    "1730793580703791926": {
+      "message": "Start pushing activity %s out to bottom task %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
+    },
+    "-8961882615747561040": {
+      "message": "Looking for task of %s in %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "8899721161806265460": {
+      "message": "Skipping task: (mismatch activity\/task) %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "6841550641928224256": {
+      "message": "Skipping %s: voice session",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "4468520936943270392": {
+      "message": "Skipping %s: different user",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-4764624740388751268": {
+      "message": "Skipping %s: mismatch root %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "9031436623838917667": {
+      "message": "Skipping %s: mismatch activity type",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "6022828946761399284": {
+      "message": "Comparing existing cls=%s \/aff=%s to new cls=%s \/aff=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-3413620974545388702": {
+      "message": "Found matching class!",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-2649361982747625232": {
+      "message": "For Intent %s bringing to top: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "7046266138098744790": {
+      "message": "Found matching affinity candidate!",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "6481733556290926693": {
+      "message": "Not a match: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "3331249072840061049": {
+      "message": "New topFocusedDisplayId=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "865845626039449679": {
+      "message": "SURFACE RECOVER DESTROY: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-4150611780753674023": {
+      "message": "Wallpaper may change!  Adjusting",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "4177291132772627699": {
+      "message": "With display frozen, orientationChangeComplete=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-5513616928833586179": {
+      "message": "Performing post-rotate rotation",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-7698723716637247994": {
+      "message": "handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w.isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "8621291657500572364": {
+      "message": "mUserActivityTimeout set to %d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-1418592110950138870": {
+      "message": "Looking for task of type=%s, taskAffinity=%s, intent=%s, info=%s, preferredTDA=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "2828976699481734755": {
+      "message": "No task found",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-4405347314716558580": {
+      "message": "Create sleep token: tag=%s, displayId=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "1329131651776855609": {
+      "message": "Remove sleep token: tag=%s, displayId=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "1653728842643223887": {
+      "message": "allResumedActivitiesIdle: rootTask=%d %s not idle",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "3785779399471740019": {
+      "message": "allPausedActivitiesComplete: r=%s state=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "4666728330189027178": {
+      "message": "Failed to register MediaProjectionWatcherCallback",
+      "level": "ERROR",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/ScreenRecordingCallbackController.java"
+    },
+    "8010999385228654193": {
+      "message": "  FREEZE %s: CREATE",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+    },
+    "-6586462455018013482": {
+      "message": "Start rotation animation. customAnim=%s, mCurRotation=%s, mOriginalRotation=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+    },
+    "-5825336546511998057": {
+      "message": "  FREEZE %s: DESTROY",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+    },
+    "6883897856740637908": {
+      "message": "ScreenRotation still animating: type: %d\nmDisplayAnimator: %s\nmEnterBlackFrameAnimator: %s\nmRotateScreenAnimator: %s\nmScreenshotRotationAnimator: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+    },
+    "-3943622313307983155": {
+      "message": "ScreenRotationAnimation onAnimationEnd",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+    },
+    "-1594708154257031561": {
+      "message": "  NEW SURFACE SESSION %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/Session.java"
+    },
+    "2638961674625826260": {
+      "message": "  KILL SURFACE SESSION %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/Session.java"
+    },
+    "5380455212389185829": {
+      "message": "Removing dim surface %s on transaction %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_DIMMER",
+      "at": "com\/android\/server\/wm\/SmoothDimmer.java"
+    },
+    "-820649637734629482": {
+      "message": "Animation start delayed for %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
+    },
+    "1371702561758591499": {
+      "message": "Animation start for %s, anim=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
+    },
+    "-5370506662233296228": {
+      "message": "Cancelling animation restarting=%b for %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
+    },
+    "-3045933321063743917": {
+      "message": "Reparenting to original parent: %s for %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
+    },
+    "-855083149623806053": {
+      "message": "Reparenting to leash for %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
+    },
+    "-2595923278763115975": {
+      "message": "  THUMBNAIL %s: CREATE",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/SurfaceFreezer.java"
+    },
+    "-8609432747982701423": {
+      "message": "Setting Intent of %s to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "-9155008290180285590": {
+      "message": "Setting Intent of %s to target %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "6424220442758232673": {
+      "message": "Removing and adding activity %s to root task at top callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "-1028890010429408946": {
+      "message": "addChild: %s at top.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "38991867929900764": {
+      "message": "setLockTaskAuth: task=%s mLockTaskAuth=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "-3401780415681318335": {
+      "message": "applyAnimationUnchecked, control: %s, task: %s, transit: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "4446998544419008924": {
+      "message": "Moving to RESUMED: %s (starting new instance) callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "4037728373502324767": {
+      "message": "resumeNextFocusableActivityWhenRootTaskIsEmpty: %s, go home",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "-2261257617975724313": {
+      "message": "Adding activity %s to task %s callers: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "7378236902389922467": {
+      "message": "App is requesting an orientation, return %d for display id=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
+    },
+    "2005499548343677845": {
+      "message": "No app is requesting an orientation, return %d for display id=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
+    },
+    "646076184396185067": {
+      "message": "App died while pausing: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-7596917112222697106": {
+      "message": "Waiting for screen on due to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-8472961767591168851": {
+      "message": "Sleep needs to pause %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-1472885369931482317": {
+      "message": "Sleep still waiting to pause %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-2693016397674039814": {
+      "message": "Sleep still need to stop %d activities",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "8892147402270850613": {
+      "message": "resumeTopActivity: Skip resume: some activity pausing.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "958293038551087087": {
+      "message": "resumeTopActivity: Top activity resumed %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "4340810061306869942": {
+      "message": "resumeTopActivity: Going to sleep and all paused",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-7681635901109618685": {
+      "message": "resumeTopActivity: Pausing %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-3463034909521330970": {
+      "message": "resumeTopActivity: Skip resume: need to start pausing",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-2264725269594226780": {
+      "message": "resumeTopActivity: Top activity resumed (dontWaitForPause) %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-8359248677489986541": {
+      "message": "Moving to RESUMED: %s (in existing)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "2088177629189452176": {
+      "message": "Activity config changed during resume: %s, new next: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-8483536760290526299": {
+      "message": "resumeTopActivity: Resumed %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-4911500660485375799": {
+      "message": "Resume failed; resetting state to %s: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "3723891427717889172": {
+      "message": "resumeTopActivity: Restarting %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "1529152423206006904": {
+      "message": "startPausing: taskFrag =%s mResumedActivity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "136971836458873178": {
+      "message": "Moving to PAUSING: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-208996201631695262": {
+      "message": "Auto-PIP allowed, requesting PIP mode via requestStartTransition(): %s, willAutoPip: %b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-4123447037565780632": {
+      "message": "Auto-PIP allowed, entering PIP mode directly: %s, didAutoPip: %b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-3710776151994843320": {
+      "message": "Key dispatch not paused for screen off",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "8543865526552245064": {
+      "message": "Activity not running or entered PiP, resuming next.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "1917394294249960915": {
+      "message": "Enqueueing pending pause: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-8936154984341817384": {
+      "message": "Complete pause: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "4971958459026584561": {
+      "message": "Executing finish of activity: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-7113165071559345173": {
+      "message": "Enqueue pending stop if needed: %s wasStopping=%b visibleRequested=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-3777748052684097788": {
+      "message": "App died during pause, not stopping: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-2808577027789344626": {
+      "message": "TaskFragment appeared name=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "-3582112419663037270": {
+      "message": "TaskFragment vanished name=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "3294593748816836746": {
+      "message": "TaskFragment info changed name=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "5007230330523630579": {
+      "message": "TaskFragment parent info changed name=%s parentTaskId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "6475066005515810081": {
+      "message": "Sending TaskFragment error exception=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "-7893265697482064583": {
+      "message": "Activity=%s reparent to taskId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "7048981249808281819": {
+      "message": "Defer transition id=%d for TaskFragmentTransaction=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "-1315509853595025526": {
+      "message": "Deferred transition id=%d has been continued before the TaskFragmentTransaction=%s is finished",
+      "level": "WARN",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "7421521217481553621": {
+      "message": "Continue transition id=%d for TaskFragmentTransaction=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "3509684748201636981": {
+      "message": "Register task fragment organizer=%s uid=%d pid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "-6777461169027010201": {
+      "message": "Unregister task fragment organizer=%s uid=%d pid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "1327792561585467865": {
+      "message": "Register remote animations for organizer=%s uid=%d pid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "-2524361347368208519": {
+      "message": "Unregister remote animations for organizer=%s uid=%d pid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "-6181189296332065162": {
+      "message": "Task appeared taskId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "6535296991997214354": {
+      "message": "Task vanished taskId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "-6638141753476761854": {
+      "message": "Task info changed taskId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "-8100069665346602959": {
+      "message": "Task back pressed on root taskId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "-610138383571469481": {
+      "message": "Register task organizer=%s uid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "1705860547080436016": {
+      "message": "Unregister task organizer=%s uid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "-2286607251115721394": {
+      "message": "createRootTask unknown displayId=%d",
+      "level": "ERROR",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "8466395828406204368": {
+      "message": "Create root task displayId=%d winMode=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "6867170298997192615": {
+      "message": "Delete root task display=%d winMode=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "-4296644831871159510": {
+      "message": "Set intercept back pressed on root=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "-558727273888268534": {
+      "message": "Restart top activity process of Task taskId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "-7064081458956324316": {
+      "message": "Update camera compat control state to %s for taskId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "3007492640459931179": {
+      "message": "Pausing rotation during re-position",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/TaskPositioner.java"
+    },
+    "5478864901888225320": {
+      "message": "Resuming rotation after re-position",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/TaskPositioner.java"
+    },
+    "-2700498872917476567": {
+      "message": "Starting a Recents transition which can be parallel.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-8676279589273455859": {
+      "message": "Transition %d: Set %s as transient-launch",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "2734227875286695843": {
+      "message": "Override sync-method for %s because seamless rotating",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "2808217645990556209": {
+      "message": "Starting Transition %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-4672522645315112127": {
+      "message": "Collecting in transition %d: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "65881049096729394": {
+      "message": " Creating Ready-group for Transition %d with root=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "1101215730201607371": {
+      "message": "Existence Changed in transition %d: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-3942072270654590479": {
+      "message": "Set transition ready=%b %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-4688704756793656554": {
+      "message": "  Commit activity becoming invisible: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "1817207111271920503": {
+      "message": "  Skipping post-transition snapshot for task %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-2960171012238790176": {
+      "message": "  Commit wallpaper becoming invisible: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "1230784960534033968": {
+      "message": "Aborting Transition: %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-892865733969888022": {
+      "message": "Force Playing Transition: %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-1354622424895965634": {
       "message": "#%d: Met condition: %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/Transition.java"
     },
-    "2128917433": {
-      "message": "onProposedRotationChanged, rotation=%d",
+    "-5350671621840749173": {
+      "message": "Calling onTransitionReady: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "1830385055586991567": {
+      "message": "Apply and finish immediately because player is disabled for transition #%d .",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-758501334967569539": {
+      "message": "      SKIP: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-2714847784842612086": {
+      "message": "      SKIP: is wallpaper",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "1855461834864671586": {
+      "message": "      check sibling %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-6292043690918793069": {
+      "message": "        SKIP: sibling is visible but not part of transition",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "7897657428993391672": {
+      "message": "        unrelated invisible sibling %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "3873493605120555608": {
+      "message": "        sibling is a participant with mode %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "7665553560859456426": {
+      "message": "          SKIP: common mode mismatch. was %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-8916099332247176657": {
+      "message": "    checking %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-6818387694968032301": {
+      "message": "      SKIP: its sibling was rejected",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-7326702978448933012": {
+      "message": "        keep as target %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "943961036184959431": {
+      "message": "        remove from targets %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "841543868388687804": {
+      "message": "      CAN PROMOTE: promoting to parent %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "743586316159041023": {
+      "message": "Start calculating TransitionInfo based on participants: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-7247430213293162757": {
+      "message": "  Rejecting as detached: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-5811837191094192313": {
+      "message": "  Rejecting as no-op: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-1153926883525904120": {
+      "message": "  Initial targets: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-9191328656870721224": {
+      "message": "  Final targets: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-2971560715211489406": {
+      "message": " Add condition %s for #%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "7631061720069910622": {
+      "message": " Met condition %s for #%d (%d left)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-4770394322045550928": {
+      "message": " Setting Ready-group to %b. group=%s from %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "6039132370452820927": {
+      "message": " Setting allReady override",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-3263748870548668913": {
+      "message": " allReady query: used=%b override=%b defer=%d states=[%s]",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "2699903406935781477": {
+      "message": "Screenshotting %s [%s]",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-233096875591058130": {
+      "message": "Creating Transition: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "2154694726162725342": {
+      "message": "Start collecting in Transition: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "-4235778637051052061": {
+      "message": "Disabling player for transition #%d because display isn't enabled yet",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "4005704720444963797": {
+      "message": "Requesting StartTransition: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "-6030030735787868329": {
+      "message": "Finish Transition: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "-1611886029896664304": {
+      "message": "Moving #%d from collecting to waiting.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "-7097461682459496366": {
+      "message": "Playing #%d in parallel on track #%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "-7364464699035275052": {
+      "message": "Marking #%d animation as SYNC.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "-5509640937151643757": {
+      "message": "Queueing transition: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "-2741593375634604522": {
+      "message": "Queueing legacy sync-set: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "-5051723169912572741": {
+      "message": "%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "4281568181321808508": {
+      "message": "    startWCT=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "5141999957143860655": {
+      "message": "    info=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "3445530300764535903": {
+      "message": "unregister failed, couldn't find deathRecipient for %s with id=%d",
+      "level": "ERROR",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "-6140852484700685564": {
+      "message": "Registering listener=%s with id=%d for window=%s with %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "3691097873058247482": {
+      "message": "Unregistering listener=%s with id=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "6408851516381868623": {
+      "message": "Checking %d windows",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "7718187745767272532": {
+      "message": "Skipping %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "-1135667737459933313": {
+      "message": "coveredRegionsAbove updated with %s frame:%s region:%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "854487339271667012": {
+      "message": "checkIfInThreshold fractionRendered=%f alpha=%f currTimeMs=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "-2248576188205088843": {
+      "message": "lastState=%s newState=%s alpha=%f minAlpha=%f fractionRendered=%f minFractionRendered=%f",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "6236170793308011579": {
+      "message": "Adding untrusted state listener=%s with id=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "5405816744363636527": {
+      "message": "Adding trusted state listener=%s with id=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "-5162728346383863020": {
+      "message": "computeFractionRendered: visibleRegion=%s screenBounds=%s contentSize=%s scale=%f,%f",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "898769258643799441": {
+      "message": "fractionRendered scale=%f",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "-455501334697331596": {
+      "message": "fractionRendered boundsOverSource=%f",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "1964980935866463086": {
+      "message": "\tWallpaper of display=%s is not visible",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
+    },
+    "8131665298937888044": {
+      "message": "startAnimation",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
+    },
+    "8030745595351281943": {
+      "message": "onAnimationCancelled",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
+    },
+    "-5254364639040552989": {
+      "message": "Hiding wallpaper %s from %s target=%s prev=%s callers=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/WallpaperController.java"
+    },
+    "-3477087868568520027": {
+      "message": "No longer animating wallpaper targets!",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/WallpaperController.java"
+    },
+    "-3751289048117070874": {
+      "message": "New wallpaper target: %s prevTarget: %s caller=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/WallpaperController.java"
+    },
+    "5625223922466895079": {
+      "message": "New animation: %s old animation: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/WallpaperController.java"
+    },
+    "7634524672408826188": {
+      "message": "Animating wallpapers: old: %s hidden=%b new: %s hidden=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/WallpaperController.java"
+    },
+    "-4345077332231178044": {
+      "message": "Old wallpaper still the target.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/WallpaperController.java"
+    },
+    "-2504764636812266719": {
+      "message": "New wallpaper: target=%s prev=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/WallpaperController.java"
+    },
+    "-7936547457136708587": {
+      "message": "Wallpaper token %s visible=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/WallpaperWindowToken.java"
+    },
+    "7214407534407465113": {
+      "message": "commitVisibility: %s: visible=%b mVisibleRequested=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WallpaperWindowToken.java"
+    },
+    "-5360147928134631656": {
+      "message": ">>> OPEN TRANSACTION animate",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowAnimator.java"
+    },
+    "-3993586364046165922": {
+      "message": "<<< CLOSE TRANSACTION animate",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowAnimator.java"
+    },
+    "-5231580410559054259": {
+      "message": "%s is requesting orientation %d (%s)",
       "level": "VERBOSE",
       "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "6949303417875346627": {
+      "message": "Starting animation on %s: type=%d, anim=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "-8730310387200541562": {
+      "message": "applyAnimation: transition animation is disabled or skipped. container=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "2363818604357955690": {
+      "message": "applyAnimation: transit=%s, enter=%b, wc=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "2262119454684034794": {
+      "message": "applyAnimation: container=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "5857165752965610762": {
+      "message": "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s surfaceInsets=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "9017113545720281233": {
+      "message": "Loaded animation %s for %s, duration: %d, stack=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "5272307326252759722": {
+      "message": "onSyncFinishedDrawing %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "-8311909671193661340": {
+      "message": "setSyncGroup #%d on %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "-3871009616397322067": {
+      "message": "finishSync cancel=%b for %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "-4267530270533009730": {
+      "message": "Error sending initial configuration change to WindowContainer overlay",
+      "level": "ERROR",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "5179630990780610966": {
+      "message": "Error sending initial insets change to WindowContainer overlay",
+      "level": "ERROR",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "-131600102855790053": {
+      "message": "  THUMBNAIL %s: CREATE",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowContainerThumbnail.java"
+    },
+    "2163930285157267092": {
+      "message": "The listener does not exist.",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowContextListenerController.java"
+    },
+    "6139364662459841509": {
+      "message": "Could not register window container listener token=%s, container=%s",
+      "level": "ERROR",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowContextListenerController.java"
+    },
+    "3655576047584951173": {
+      "message": "Window Manager Crash %s",
+      "level": "WTF",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-3029436704707366221": {
+      "message": "Attempted to add window with a client %s that is dead. Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1303710477998542095": {
+      "message": "Attempted to add window to a display that does not exist: %d. Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8039410207325630747": {
+      "message": "Attempted to add window to a display for which the application does not have access: %d.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-3451016577701561221": {
+      "message": "Window %s is already added",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "7245919222637411747": {
+      "message": "Attempted to add window with token that is not a window: %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-8579305050440451727": {
+      "message": "Attempted to add window with token that is a sub-window: %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1075040941127814341": {
+      "message": "Attempted to add private presentation window to a non-private display.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "7599690046549866326": {
+      "message": "Attempted to add presentation window to a non-suitable display.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2546047231197102533": {
+      "message": "Trying to add window with invalid user=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "3713874359318494804": {
+      "message": "Attempted to add window with non-application token .%s Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6507147599943157469": {
+      "message": "Attempted to add window with exiting application token .%s Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1409483453189443362": {
+      "message": "Attempted to add starting window to token with already existing starting window",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1806907994917883598": {
+      "message": "Attempted to add starting window to token but already cleaned",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-5450131464624918523": {
+      "message": "Attempted to add input method window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6484128707849211138": {
+      "message": "Attempted to add voice interaction window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "7768591536609704658": {
+      "message": "Attempted to add wallpaper window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "7497077135474110999": {
+      "message": "Attempted to add Accessibility overlay window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8957851092580119204": {
+      "message": "Attempted to add a toast window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1945746969404688952": {
+      "message": "Attempted to add QS dialog window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "3419934373251134563": {
+      "message": "Non-null activity for system window of rootType=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1161056447389155729": {
+      "message": "Adding more than one toast window for UID at a time.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-7518552252637236411": {
+      "message": "Window types in WindowContext and LayoutParams.type should match! Type from LayoutParams is %d, but type from WindowContext is %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6055615852717459196": {
+      "message": "addWindow: %s startingWindow=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2829980616540274784": {
+      "message": "addWindow: New client %s: window=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-7315179333005789167": {
+      "message": "Attempted to add application window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-7547709658889961930": {
+      "message": "Attempted to add input method window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "3009864422591182484": {
+      "message": "Attempted to add voice interaction window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2639914438438144071": {
+      "message": "Attempted to add wallpaper window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-7529563697886120786": {
+      "message": "Attempted to add QS dialog window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "4253401518117961686": {
+      "message": "Attempted to add Accessibility overlay window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "5834230650841873680": {
+      "message": "Attempted to add a toast window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "5265273548711408921": {
+      "message": "postWindowRemoveCleanupLocked: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-3847568084407666790": {
+      "message": "Final remove of window: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_MOVEMENT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1419572818243106725": {
+      "message": "Removing %s from %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8312693933819247897": {
+      "message": "Relayout %s: oldVis=%d newVis=%d. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8319702790708803735": {
+      "message": "Exception thrown when creating surface for client %s (%s). %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "212929172223901460": {
+      "message": "Relayout of %s: focusMayChange=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-255991894956556845": {
+      "message": "Set animatingExit: reason=startExitingAnimation\/%s win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "6555160513135851764": {
+      "message": "OUT SURFACE %s: copied",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-196459205494031145": {
+      "message": "Failed to create surface control for %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-5512006943172316333": {
+      "message": "finishDrawingWindow: %s mDrawState=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2577785761087081584": {
+      "message": "Permission Denial: %s from pid=%d, uid=%d requires %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "4547566763172245740": {
+      "message": "addWindowToken: Attempted to add token: %s for non-exiting displayId=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-972832559831959983": {
+      "message": "addWindowToken: Attempted to add binder token: %s for already created window token: %s displayId=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8372202339190060748": {
+      "message": "attachWindowContextToDisplayArea: calling from non-existing process pid=%d uid=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1904306629015452865": {
+      "message": "attachWindowContextToDisplayArea: trying to attach to a non-existing display:%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6845859096032432107": {
+      "message": "attachWindowContextToDisplayContent: calling from non-existing process pid=%d uid=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1473791807245791604": {
+      "message": "attachWindowContextToWindowToken: calling from non-existing process pid=%d uid=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2056866750160555704": {
+      "message": "Then token:%s is invalid. It might be removed",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1045756671264607145": {
+      "message": "removeWindowToken: Attempted to remove token: %s for non-exiting displayId=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "874825105313641295": {
+      "message": "removeWindowToken: Attempted to remove non-existing token: %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "5128669121055635771": {
+      "message": "moveWindowTokenToDisplay: Attempted to move token: %s to non-exiting displayId=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "6497954191906583839": {
+      "message": "moveWindowTokenToDisplay: Attempted to move non-existing token: %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "2865882097969084039": {
+      "message": "moveWindowTokenToDisplay: Cannot move to the original display for token: %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-886583195545553099": {
+      "message": "Not moving display (displayId=%d) to top. Top focused displayId=%d. Reason: FLAG_STEAL_TOP_FOCUS_DISABLED",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1557387535886241553": {
+      "message": "enableScreenAfterBoot: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6467850045030187736": {
+      "message": "enableScreenIfNeededLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "179762478329442868": {
+      "message": "***** BOOT TIMEOUT: forcing display enabled",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-3417569256875279779": {
+      "message": "performEnableScreen: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-7516915153725082358": {
+      "message": "performEnableScreen: Waited %dms for all windows to be drawn",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1541244520024033685": {
+      "message": "performEnableScreen: Waiting for anim complete",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "2670150656385758826": {
+      "message": "performEnableScreen: bootFinished() failed.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "530628508916855904": {
+      "message": "******************** ENABLING SCREEN!",
+      "level": "INFO",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "5477889324043875194": {
+      "message": "Notified TransitionController that the display is ready.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2061779801633179448": {
+      "message": "checkBootAnimationComplete: Waiting for anim complete",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-8177456840019985809": {
+      "message": "checkBootAnimationComplete: Animation complete!",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-333924817004774456": {
+      "message": "showBootMessage: msg=%s always=%b mAllowBootMessages=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "2994810644159608200": {
+      "message": "hideBootMessagesLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6625203651195752178": {
+      "message": "freezeDisplayRotation: current rotation=%d, new rotation=%d, caller=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8988910478484254861": {
+      "message": "thawRotation: mRotation=%d, caller=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "7261084872394224738": {
+      "message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8664813170125714536": {
+      "message": "View server did not start",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-8019372496359375449": {
+      "message": "Could not send command %s with parameters %s. %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1893303527772009363": {
+      "message": "Devices still not ready after waiting %d milliseconds before attempting to detect safe mode.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-3652974372240081071": {
+      "message": "SAFE MODE ENABLED (menu=%d s=%d dpad=%d trackball=%d)",
+      "level": "INFO",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "4945624619344146947": {
+      "message": "SAFE MODE not enabled",
+      "level": "INFO",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-3428027271337724889": {
+      "message": "Focus changing: %s -> %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1624328195833150047": {
+      "message": "App freeze timeout expired.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "5830724144971462783": {
+      "message": "Timeout waiting for drawn: undrawn=%s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2240705227895260140": {
+      "message": "CHECK_IF_BOOT_ANIMATION_FINISHED:",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8641557333789260779": {
+      "message": "FORCED DISPLAY SIZE: %dx%d",
+      "level": "INFO",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "3781141652793604337": {
+      "message": "FORCED DISPLAY SCALING DISABLED",
+      "level": "INFO",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "4117606810523219596": {
+      "message": "Failed looking up window session=%s callers=%s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1233670725456443473": {
+      "message": "Changing surface while display frozen: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1716033239040181528": {
+      "message": "Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d",
+      "level": "INFO",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-4609828204247499633": {
+      "message": "Aborted waiting for drawn: %s",
+      "level": "WARN",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-7561054602203220590": {
+      "message": "Window drawn win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "2809030008663191766": {
+      "message": "All windows drawn!",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1615905649072328410": {
+      "message": "startFreezingDisplayLocked: exitAnim=%d enterAnim=%d called by %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "4565793239453546297": {
+      "message": "stopFreezingDisplayLocked: Returning waitingForConfig=%b, waitingForRemoteDisplayChange=%b, mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, mClientFreezingScreen=%b, mOpeningApps.size()=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6877112251967196129": {
+      "message": "stopFreezingDisplayLocked: Unfreezing now",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "721393258715103117": {
+      "message": "%s",
+      "level": "INFO",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-5706083447992207254": {
+      "message": "**** Dismissing screen rotation animation",
+      "level": "INFO",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "2233371241933584073": {
+      "message": "Performing post-rotate rotation",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1010635158502326025": {
+      "message": "unable to call receiver for empty keyboard shortcuts",
+      "level": "ERROR",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1278715281433572858": {
+      "message": "Bad requesting window %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-707915937966769475": {
+      "message": "unable to update pointer icon",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-8663841671650918687": {
+      "message": "unable to restore pointer icon",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6186782212018913664": {
+      "message": "Invalid displayId for requestScrollCapture: %d",
+      "level": "ERROR",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "51378282333944649": {
+      "message": "requestScrollCapture: caught exception dispatching to window.token=%s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-8972916676375201577": {
+      "message": "requestScrollCapture: caught exception dispatching callback: %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1875125162673622728": {
+      "message": "Attempted to get windowing mode of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "3938331948687900219": {
+      "message": "Attempted to set windowing mode to a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "4200292050699107329": {
+      "message": "Attempted to get remove mode of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-5574580669790275797": {
+      "message": "Attempted to set remove mode to a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "525945815055875796": {
+      "message": "Attempted to get flag of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8186524992939307511": {
+      "message": "Attempted to set flag to a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-600035824255550632": {
+      "message": "Attempted to get system decors flag of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "3056518663346732662": {
+      "message": "Attempted to set system decors flag to a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "5177195624625618567": {
+      "message": "Attempted to get IME policy of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "3932627933834459400": {
+      "message": "Attempted to set IME policy to a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "5770211341769258866": {
+      "message": "setWallpaperShowWhenLocked: non-existent wallpaper token: %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "698926505694016512": {
+      "message": "setWallpaperCropHints: non-existent wallpaper token: %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-7428028317216329062": {
+      "message": "hideIme target: %s ",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1006302987953651112": {
+      "message": "hideIme Control target: %s ",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "5213970642134448962": {
+      "message": "Attempted to get home support flag of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2065144681579661392": {
+      "message": "onPointerDownOutsideFocusLocked called on %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-7394143854567081754": {
+      "message": "grantEmbeddedWindowFocus win=%s dropped focus so setting focus to null since no candidate was found",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6056928081282320632": {
+      "message": "grantEmbeddedWindowFocus win=%s grantFocus=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "6110791601270766802": {
+      "message": "TaskFragmentTransaction changes are not collected in transition because there is an ongoing sync for applySyncTransaction().",
+      "level": "WARN",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+    },
+    "9200403125156001641": {
+      "message": "Apply window transaction, syncId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+    },
+    "433446585990132440": {
+      "message": "Set sync ready, syncId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+    },
+    "6552038620140878489": {
+      "message": "Transaction ready, syncId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+    },
+    "-4629255026637000251": {
+      "message": "Sending to proc %s new config %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/WindowProcessController.java"
+    },
+    "-7237767461056267619": {
+      "message": "%s: Setting back callback %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "8135615413833185273": {
+      "message": "Adding %s to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "8842744325264128950": {
+      "message": "Resize reasons for w=%s:  %s configChanged=%b didFrameInsetsChange=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_RESIZE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-8636590597069784069": {
+      "message": "Resizing window %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_RESIZE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-2710188685736986208": {
+      "message": "Orientation not waiting for draw in %s, surfaceController %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "5236278969232209904": {
+      "message": "onMovedByResize: Moving %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RESIZE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "7646042751617940718": {
+      "message": "Set animatingExit: reason=onAppVisibilityChanged win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "1783521309242112490": {
+      "message": "onResize: Resizing %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RESIZE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "1351053513466395411": {
+      "message": "WS.removeImmediately: %s Already removed...",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "3927343382258792268": {
+      "message": "removeIfPossible: %s callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-4831815184899821371": {
+      "message": "Starting window removed %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-5803097884846965819": {
+      "message": "Remove client=%x, surfaceController=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-2547748024041128829": {
+      "message": "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b mDisplayFrozen=%b callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "7789778354950913237": {
+      "message": "Set animatingExit: reason=remove\/applyAnimation win=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-4143841388126586338": {
+      "message": "Not removing %s due to exit animation",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "4419190702135590390": {
+      "message": "Set animatingExit: reason=remove\/isAnimating win=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-6167820560758523840": {
+      "message": "setAnimationLocked: setting mFocusMayChange true",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-208079497999140637": {
+      "message": "WindowState.hideLw: setting mFocusMayChange true",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "8812513438749898553": {
+      "message": "set mOrientationChanging of %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-2964267636425934067": {
+      "message": "win=%s destroySurfaces: appStopped=%b win.mWindowRemovalAllowed=%b win.mRemoveOnExit=%b",
+      "level": "ERROR",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "7336961102428192483": {
+      "message": "Clear animatingExit: reason=destroySurface win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-6920306331987525705": {
+      "message": "Reporting new frame to %s: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_RESIZE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "2714651498627020992": {
+      "message": "Resizing %s WITH DRAW PENDING",
+      "level": "INFO",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-5755338358883139945": {
+      "message": "Requested redraw for orientation change: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-5211036212243647844": {
+      "message": "notifyInsetsChanged for %s ",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-3186229270467822891": {
+      "message": "notifyInsetsControlChanged for %s ",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-7413136364930452718": {
+      "message": "performShowLocked: mDrawState=HAS_DRAWN in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "7624470121297688739": {
+      "message": "shouldWaitAnimatingExit: isTransition: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "810267895099109466": {
+      "message": "shouldWaitAnimatingExit: isAnimating: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-1760879391350377377": {
+      "message": "shouldWaitAnimatingExit: isWallpaperTarget: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "272960397873328729": {
+      "message": "Clear window stuck on animatingExit status: %s",
+      "level": "WARN",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-1007526574020149845": {
+      "message": "onExitAnimationDone in %s: exiting=%b remove=%b selfAnimating=%b anim=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "1738645946553610841": {
+      "message": "Exit animation finished in %s: remove=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-7737516306844862315": {
+      "message": "Clear animatingExit: reason=exitAnimationDone win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-3153130647145726082": {
+      "message": "Clear animatingExit: reason=clearAnimatingFlags win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-5202247309108694583": {
+      "message": "Clear animatingExit: reason=relayoutVisibleWindow win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "6291563604478341956": {
+      "message": "Setting move animation on %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-5774445199273871848": {
+      "message": "Preparing to sync a window that was already in the sync, so try dropping buffer. win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "8097934579596343476": {
+      "message": "Got a buffer for request id=%d but latest request is id=%d. Since the buffer is out-of-date, drop it. win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "8269653477215188641": {
+      "message": "SURFACE isSecure=%b: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-1495677286613044867": {
+      "message": "Animation done in %s: exiting=%b, reportedVisible=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "3436877176443058520": {
+      "message": "Finishing drawing window %s: mDrawState=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "345647873457403698": {
+      "message": "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING %s in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_DRAW",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-2385558637577093121": {
+      "message": "Draw state now committed in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-3490933626936411542": {
+      "message": "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-6088246515441976339": {
+      "message": "createSurface %s: mDrawState=DRAW_PENDING",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "2353125758087345363": {
+      "message": "  CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x \/ %s",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-4491856282178275074": {
+      "message": "SURFACE DESTROY: %s. %s",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "8602950884833508970": {
+      "message": "Orientation change skips hidden %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-5079712802591263622": {
+      "message": "SURFACE controller=%s alpha=%f HScale=%f, VScale=%f: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-2824875917893878016": {
+      "message": "Orientation continue waiting for draw in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "7457181879495900576": {
+      "message": "Orientation change complete in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-5668794009329913533": {
+      "message": "applyAnimation: win=%s anim=%d attr=0x%x a=%s transit=%d type=%d isEntrance=%b Callers %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-2055407587764455051": {
+      "message": "SURFACE HIDE ( %s ): %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "-5854683348829455340": {
+      "message": "Destroying surface %s called by %s",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "7813672046338784579": {
+      "message": "SURFACE isOpaque=%b: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "-8864150640874799238": {
+      "message": "SURFACE isColorSpaceAgnostic=%b: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "-8398940245851553814": {
+      "message": "SURFACE SHOW (performLayout): %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "8174298531248485625": {
+      "message": "removeAllWindowsIfPossible: removing win=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_WINDOW_MOVEMENT",
+      "at": "com\/android\/server\/wm\/WindowToken.java"
+    },
+    "2740931087734487464": {
+      "message": "addWindow: win=%s Callers=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/WindowToken.java"
+    },
+    "2382798629637143561": {
+      "message": "Adding %s to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowToken.java"
+    },
+    "-7314975896738778749": {
+      "message": "setClientVisible: %s clientVisible=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowToken.java"
     }
   },
   "groups": {
diff --git a/data/fonts/font_fallback.xml b/data/fonts/font_fallback.xml
index 15ea15a..53024ab 100644
--- a/data/fonts/font_fallback.xml
+++ b/data/fonts/font_fallback.xml
@@ -792,14 +792,10 @@
         </font>
     </family>
     <family lang="ja">
-        <font weight="400" style="normal">
-            NotoSerifHentaigana-EL.ttf
+        <font postScriptName="NotoSerifHentaigana-ExtraLight" supportedAxes="wght">
+            NotoSerifHentaigana.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="700" style="normal">
-            NotoSerifHentaigana-EL.ttf
-          <axis tag="wght" stylevalue="700"/>
-        </font>
     </family>
     <family lang="ko">
         <font weight="400" style="normal" index="1" postScriptName="NotoSansCJKjp-Regular">
diff --git a/data/fonts/font_fallback_cjkvf.xml b/data/fonts/font_fallback_cjkvf.xml
index c1ca67e..ac1b064 100644
--- a/data/fonts/font_fallback_cjkvf.xml
+++ b/data/fonts/font_fallback_cjkvf.xml
@@ -804,14 +804,10 @@
         </font>
     </family>
     <family lang="ja">
-        <font weight="400" style="normal">
-            NotoSerifHentaigana-EL.ttf
+        <font postScriptName="NotoSerifHentaigana-ExtraLight" supportedAxes="wght">
+            NotoSerifHentaigana.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="700" style="normal">
-            NotoSerifHentaigana-EL.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
     </family>
     <family lang="ko">
         <font weight="400" style="normal" index="1" postScriptName="NotoSansCJKjp-Thin"
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index b23f005..d1aa8e9 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -1433,12 +1433,12 @@
         </font>
     </family>
     <family lang="ja">
-        <font weight="400" style="normal">
-            NotoSerifHentaigana-EL.ttf
+        <font weight="400" style="normal" postScriptName="NotoSerifHentaigana-ExtraLight">
+            NotoSerifHentaigana.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="700" style="normal">
-            NotoSerifHentaigana-EL.ttf
+        <font weight="700" style="normal" postScriptName="NotoSerifHentaigana-ExtraLight">
+            NotoSerifHentaigana.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
diff --git a/data/fonts/fonts_cjkvf.xml b/data/fonts/fonts_cjkvf.xml
index 1ab71ae..9545ae7 100644
--- a/data/fonts/fonts_cjkvf.xml
+++ b/data/fonts/fonts_cjkvf.xml
@@ -1532,12 +1532,12 @@
         </font>
     </family>
     <family lang="ja">
-        <font weight="400" style="normal">
-            NotoSerifHentaigana-EL.ttf
+        <font weight="400" style="normal" postScriptName="NotoSerifHentaigana-ExtraLight">
+            NotoSerifHentaigana.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="700" style="normal">
-            NotoSerifHentaigana-EL.ttf
+        <font weight="700" style="normal" postScriptName="NotoSerifHentaigana-ExtraLight">
+            NotoSerifHentaigana.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
diff --git a/graphics/java/android/graphics/text/MeasuredText.java b/graphics/java/android/graphics/text/MeasuredText.java
index 6da0719..884268a 100644
--- a/graphics/java/android/graphics/text/MeasuredText.java
+++ b/graphics/java/android/graphics/text/MeasuredText.java
@@ -29,11 +29,13 @@
 import com.android.internal.util.Preconditions;
 
 import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.NeverInline;
 
 import libcore.util.NativeAllocationRegistry;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Locale;
 import java.util.Objects;
 
 /**
@@ -85,6 +87,30 @@
         return mChars;
     }
 
+    private void rangeCheck(int start, int end) {
+        if (start < 0 || start > end || end > mChars.length) {
+            throwRangeError(start, end);
+        }
+    }
+
+    @NeverInline
+    private void throwRangeError(int start, int end) {
+        throw new IllegalArgumentException(String.format(Locale.US,
+            "start(%d) end(%d) length(%d) out of bounds", start, end, mChars.length));
+    }
+
+    private void offsetCheck(int offset) {
+        if (offset < 0 || offset >= mChars.length) {
+            throwOffsetError(offset);
+        }
+    }
+
+    @NeverInline
+    private void throwOffsetError(int offset) {
+        throw new IllegalArgumentException(String.format(Locale.US,
+            "offset (%d) length(%d) out of bounds", offset, mChars.length));
+    }
+
     /**
      * Returns the width of a given range.
      *
@@ -93,12 +119,7 @@
      */
     public @FloatRange(from = 0.0) @Px float getWidth(
             @IntRange(from = 0) int start, @IntRange(from = 0) int end) {
-        Preconditions.checkArgument(0 <= start && start <= mChars.length,
-                "start(%d) must be 0 <= start <= %d", start, mChars.length);
-        Preconditions.checkArgument(0 <= end && end <= mChars.length,
-                "end(%d) must be 0 <= end <= %d", end, mChars.length);
-        Preconditions.checkArgument(start <= end,
-                "start(%d) is larger than end(%d)", start, end);
+        rangeCheck(start, end);
         return nGetWidth(mNativePtr, start, end);
     }
 
@@ -120,12 +141,7 @@
      */
     public void getBounds(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
             @NonNull Rect rect) {
-        Preconditions.checkArgument(0 <= start && start <= mChars.length,
-                "start(%d) must be 0 <= start <= %d", start, mChars.length);
-        Preconditions.checkArgument(0 <= end && end <= mChars.length,
-                "end(%d) must be 0 <= end <= %d", end, mChars.length);
-        Preconditions.checkArgument(start <= end,
-                "start(%d) is larger than end(%d)", start, end);
+        rangeCheck(start, end);
         Preconditions.checkNotNull(rect);
         nGetBounds(mNativePtr, mChars, start, end, rect);
     }
@@ -139,12 +155,7 @@
      */
     public void getFontMetricsInt(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
             @NonNull Paint.FontMetricsInt outMetrics) {
-        Preconditions.checkArgument(0 <= start && start <= mChars.length,
-                "start(%d) must be 0 <= start <= %d", start, mChars.length);
-        Preconditions.checkArgument(0 <= end && end <= mChars.length,
-                "end(%d) must be 0 <= end <= %d", end, mChars.length);
-        Preconditions.checkArgument(start <= end,
-                "start(%d) is larger than end(%d)", start, end);
+        rangeCheck(start, end);
         Objects.requireNonNull(outMetrics);
 
         long packed = nGetExtent(mNativePtr, mChars, start, end);
@@ -160,8 +171,7 @@
      * @param offset an offset of the character.
      */
     public @FloatRange(from = 0.0f) @Px float getCharWidthAt(@IntRange(from = 0) int offset) {
-        Preconditions.checkArgument(0 <= offset && offset < mChars.length,
-                "offset(%d) is larger than text length %d" + offset, mChars.length);
+        offsetCheck(offset);
         return nGetCharWidthAt(mNativePtr, offset);
     }
 
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 11b8271..bd9abec 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -21,12 +21,14 @@
 import android.os.StrictMode;
 
 /**
- * @hide This should not be made public in its present form because it
- * assumes that private and secret key bytes are available and would
- * preclude the use of hardware crypto.
+ * This class provides some constants and helper methods related to Android's Keystore service.
+ * This class was originally much larger, but its functionality was superseded by other classes.
+ * It now just contains a few remaining pieces for which the users haven't been updated yet.
+ * You may be looking for {@link java.security.KeyStore} instead.
+ *
+ * @hide
  */
 public class KeyStore {
-    private static final String TAG = "KeyStore";
 
     // ResponseCodes - see system/security/keystore/include/keystore/keystore.h
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -42,50 +44,6 @@
         return KEY_STORE;
     }
 
-    /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public byte[] get(String key) {
-        return null;
-    }
-
-    /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public boolean delete(String key) {
-        return false;
-    }
-
-    /**
-     * List uids of all keys that are auth bound to the current user.
-     * Only system is allowed to call this method.
-     * @hide
-     * @deprecated This function always returns null.
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public int[] listUidsOfAuthBoundKeys() {
-        return null;
-    }
-
-
-    /**
-     * @hide
-     * @deprecated This function has no effect.
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public boolean unlock(String password) {
-        return false;
-    }
-
-    /**
-     *
-     * @return
-     * @deprecated This function always returns true.
-     * @hide
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    public boolean isEmpty() {
-        return true;
-    }
-
     /**
      * Add an authentication record to the keystore authorization table.
      *
@@ -105,13 +63,4 @@
     public void onDeviceOffBody() {
         AndroidKeyStoreMaintenance.onDeviceOffBody();
     }
-
-    /**
-     * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
-     * code.
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static KeyStoreException getKeyStoreException(int errorCode) {
-        return new KeyStoreException(-10000, "Should not be called.");
-    }
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index 62fe54f..ef03d3a 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -19,9 +19,9 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
-import android.security.KeyStore;
 
 import java.io.IOException;
+import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
@@ -47,13 +47,13 @@
     }
 
     /**
-     * Gets the {@link KeyStore} operation handle corresponding to the provided JCA crypto
+     * Gets the Android KeyStore operation handle corresponding to the provided JCA crypto
      * primitive.
      *
      * <p>The following primitives are supported: {@link Cipher} and {@link Mac}.
      *
-     * @return KeyStore operation handle or {@code 0} if the provided primitive's KeyStore operation
-     *         is not in progress.
+     * @return Android KeyStore operation handle or {@code 0} if the provided primitive's Android
+     *         KeyStore operation is not in progress.
      *
      * @throws IllegalArgumentException if the provided primitive is not supported or is not backed
      *         by AndroidKeyStore provider.
@@ -67,10 +67,10 @@
     }
 
     /**
-     * Returns an {@code AndroidKeyStore} {@link java.security.KeyStore}} of the specified UID.
-     * The {@code KeyStore} contains keys and certificates owned by that UID. Such cross-UID
-     * access is permitted to a few system UIDs and only to a few other UIDs (e.g., Wi-Fi, VPN)
-     * all of which are system.
+     * Returns an {@code AndroidKeyStore} {@link KeyStore} of the specified UID. The {@code
+     * KeyStore} contains keys and certificates owned by that UID. Such cross-UID access is
+     * permitted to a few system UIDs and only to a few other UIDs (e.g., Wi-Fi, VPN) all of which
+     * are system.
      *
      * <p>Note: the returned {@code KeyStore} is already initialized/loaded. Thus, there is
      * no need to invoke {@code load} on it.
@@ -84,12 +84,12 @@
      */
     @SystemApi
     @NonNull
-    public static java.security.KeyStore getKeyStoreForUid(int uid)
+    public static KeyStore getKeyStoreForUid(int uid)
             throws KeyStoreException, NoSuchProviderException {
-        final java.security.KeyStore.LoadStoreParameter loadParameter =
+        final KeyStore.LoadStoreParameter loadParameter =
                 new android.security.keystore2.AndroidKeyStoreLoadStoreParameter(
                         KeyProperties.legacyUidToNamespace(uid));
-        java.security.KeyStore result = java.security.KeyStore.getInstance(PROVIDER_NAME);
+        KeyStore result = KeyStore.getInstance(PROVIDER_NAME);
         try {
             result.load(loadParameter);
         } catch (NoSuchAlgorithmException | CertificateException | IOException e) {
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 244fe30..7aecfd8 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -910,7 +910,7 @@
     /**
      * Returns whether this key is critical to the device encryption flow.
      *
-     * @see android.security.KeyStore#FLAG_CRITICAL_TO_DEVICE_ENCRYPTION
+     * @see Builder#setCriticalToDeviceEncryption(boolean)
      * @hide
      */
     public boolean isCriticalToDeviceEncryption() {
diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java
index f50efd2..5cffe46 100644
--- a/keystore/java/android/security/keystore/KeyInfo.java
+++ b/keystore/java/android/security/keystore/KeyInfo.java
@@ -16,6 +16,7 @@
 
 package android.security.keystore;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 
@@ -81,6 +82,7 @@
     private final @KeyProperties.AuthEnum int mUserAuthenticationType;
     private final boolean mUserAuthenticationRequirementEnforcedBySecureHardware;
     private final boolean mUserAuthenticationValidWhileOnBody;
+    private final boolean mUnlockedDeviceRequired;
     private final boolean mTrustedUserPresenceRequired;
     private final boolean mInvalidatedByBiometricEnrollment;
     private final boolean mUserConfirmationRequired;
@@ -107,6 +109,7 @@
             @KeyProperties.AuthEnum int userAuthenticationType,
             boolean userAuthenticationRequirementEnforcedBySecureHardware,
             boolean userAuthenticationValidWhileOnBody,
+            boolean unlockedDeviceRequired,
             boolean trustedUserPresenceRequired,
             boolean invalidatedByBiometricEnrollment,
             boolean userConfirmationRequired,
@@ -132,6 +135,7 @@
         mUserAuthenticationRequirementEnforcedBySecureHardware =
                 userAuthenticationRequirementEnforcedBySecureHardware;
         mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
+        mUnlockedDeviceRequired = unlockedDeviceRequired;
         mTrustedUserPresenceRequired = trustedUserPresenceRequired;
         mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
         mUserConfirmationRequired = userConfirmationRequired;
@@ -275,6 +279,20 @@
     }
 
     /**
+     * Returns {@code true} if the key is authorized to be used only when the device is unlocked.
+     *
+     * <p>This authorization applies only to secret key and private key operations. Public key
+     * operations are not restricted.
+     *
+     * @see KeyGenParameterSpec.Builder#setUnlockedDeviceRequired(boolean)
+     * @see KeyProtection.Builder#setUnlockedDeviceRequired(boolean)
+     */
+    @FlaggedApi(android.security.Flags.FLAG_KEYINFO_UNLOCKED_DEVICE_REQUIRED)
+    public boolean isUnlockedDeviceRequired() {
+        return mUnlockedDeviceRequired;
+    }
+
+    /**
      * Returns {@code true} if the key is authorized to be used only for messages confirmed by the
      * user.
      *
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 2495d1a..31b4a5e 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -569,7 +569,7 @@
     /**
      * Return whether this key is critical to the device encryption flow.
      *
-     * @see android.security.KeyStore#FLAG_CRITICAL_TO_DEVICE_ENCRYPTION
+     * @see Builder#setCriticalToDeviceEncryption(boolean)
      * @hide
      */
     public boolean isCriticalToDeviceEncryption() {
@@ -1105,9 +1105,10 @@
          * Set whether this key is critical to the device encryption flow
          *
          * This is a special flag only available to system servers to indicate the current key
-         * is part of the device encryption flow.
+         * is part of the device encryption flow. Setting this flag causes the key to not
+         * be cryptographically bound to the LSKF even if the key is otherwise authentication
+         * bound.
          *
-         * @see android.security.KeyStore#FLAG_CRITICAL_TO_DEVICE_ENCRYPTION
          * @hide
          */
         public Builder setCriticalToDeviceEncryption(boolean critical) {
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperation.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperation.java
index 2c709ae..c42c9e4 100644
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperation.java
+++ b/keystore/java/android/security/keystore/KeyStoreCryptoOperation.java
@@ -16,18 +16,16 @@
 
 package android.security.keystore;
 
-import android.security.KeyStore;
-
 /**
- * Cryptographic operation backed by {@link KeyStore}.
+ * Cryptographic operation backed by Android KeyStore.
  *
  * @hide
  */
 public interface KeyStoreCryptoOperation {
     /**
-     * Gets the KeyStore operation handle of this crypto operation.
+     * Gets the Android KeyStore operation handle of this crypto operation.
      *
-     * @return handle or {@code 0} if the KeyStore operation is not in progress.
+     * @return handle or {@code 0} if the Android KeyStore operation is not in progress.
      */
     long getOperationHandle();
 }
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyFactorySpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyFactorySpi.java
index a8dd7f3..8eca67f 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyFactorySpi.java
@@ -16,7 +16,6 @@
 
 package android.security.keystore2;
 
-import android.security.KeyStore;
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyInfo;
 
@@ -39,8 +38,6 @@
  */
 public class AndroidKeyStoreKeyFactorySpi extends KeyFactorySpi {
 
-    private final KeyStore mKeyStore = KeyStore.getInstance();
-
     @Override
     protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpecClass)
             throws InvalidKeySpecException {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index d204f13..99100de 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -17,7 +17,6 @@
 package android.security.keystore2;
 
 import android.annotation.NonNull;
-import android.security.KeyStore;
 import android.security.KeyStore2;
 import android.security.KeyStoreSecurityLevel;
 import android.security.keymaster.KeymasterDefs;
@@ -161,13 +160,13 @@
     }
 
     /**
-     * Gets the {@link KeyStore} operation handle corresponding to the provided JCA crypto
+     * Gets the Android KeyStore operation handle corresponding to the provided JCA crypto
      * primitive.
      *
      * <p>The following primitives are supported: {@link Cipher}, {@link Signature} and {@link Mac}.
      *
-     * @return KeyStore operation handle or {@code 0} if the provided primitive's KeyStore operation
-     *         is not in progress.
+     * @return Android KeyStore operation handle or {@code 0} if the provided primitive's Android
+     *         KeyStore operation is not in progress.
      *
      * @throws IllegalArgumentException if the provided primitive is not supported or is not backed
      *         by AndroidKeyStore provider.
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
index 97592b4..2223091 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.security.GateKeeper;
-import android.security.KeyStore;
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
 import android.security.keystore.KeyGenParameterSpec;
@@ -46,8 +45,6 @@
  */
 public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
 
-    private final KeyStore mKeyStore = KeyStore.getInstance();
-
     @Override
     protected KeySpec engineGetKeySpec(SecretKey key,
             @SuppressWarnings("rawtypes") Class keySpecClass) throws InvalidKeySpecException {
@@ -93,6 +90,7 @@
         long userAuthenticationValidityDurationSeconds = 0;
         boolean userAuthenticationRequired = true;
         boolean userAuthenticationValidWhileOnBody = false;
+        boolean unlockedDeviceRequired = false;
         boolean trustedUserPresenceRequired = false;
         boolean trustedUserConfirmationRequired = false;
         int remainingUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT;
@@ -184,6 +182,9 @@
                                     + userAuthenticationValidityDurationSeconds + " seconds");
                         }
                         break;
+                    case KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED:
+                        unlockedDeviceRequired = true;
+                        break;
                     case KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY:
                         userAuthenticationValidWhileOnBody =
                                 KeyStore2ParameterUtils.isSecureHardware(a.securityLevel);
@@ -257,6 +258,7 @@
                         : keymasterSwEnforcedUserAuthenticators,
                 userAuthenticationRequirementEnforcedBySecureHardware,
                 userAuthenticationValidWhileOnBody,
+                unlockedDeviceRequired,
                 trustedUserPresenceRequired,
                 invalidatedByBiometricEnrollment,
                 trustedUserConfirmationRequired,
diff --git a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationStreamer.java b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationStreamer.java
index 07d6a69..5bd98bc 100644
--- a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationStreamer.java
+++ b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationStreamer.java
@@ -16,12 +16,11 @@
 
 package android.security.keystore2;
 
-import android.security.KeyStore;
 import android.security.KeyStoreException;
 
 /**
- * Helper for streaming a crypto operation's input and output via {@link KeyStore} service's
- * {@code update} and {@code finish} operations.
+ * Helper for streaming a crypto operation's input and output via KeyStore service's {@code update}
+ * and {@code finish} operations.
  *
  * <p>The helper abstracts away to issues that need to be solved in most code that uses KeyStore's
  * update and finish operations. Firstly, KeyStore's update operation can consume only a limited
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java
index 65955b1..e37dea4 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java
@@ -126,7 +126,7 @@
      * @see #FEATURE_PATTERN
      * @return {@link List} of {@link CommonFoldingFeature}.
      */
-    static List<CommonFoldingFeature> parseListFromString(@NonNull String value,
+    public static List<CommonFoldingFeature> parseListFromString(@NonNull String value,
             @State int hingeState) {
         List<CommonFoldingFeature> features = new ArrayList<>();
         String[] featureStrings =  value.split(";");
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
index a184dff..88fd461 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
@@ -36,6 +36,7 @@
 import com.android.internal.R;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
@@ -78,7 +79,9 @@
     private int mCurrentBaseDeviceState = INVALID_DEVICE_STATE;
 
     @NonNull
-    private final BaseDataProducer<String> mRawFoldSupplier;
+    private final RawFoldingFeatureProducer mRawFoldSupplier;
+
+    private final boolean mIsHalfOpenedSupported;
 
     private final DeviceStateCallback mDeviceStateCallback = new DeviceStateCallback() {
         @Override
@@ -101,10 +104,12 @@
     };
 
     public DeviceStateManagerFoldingFeatureProducer(@NonNull Context context,
-            @NonNull BaseDataProducer<String> rawFoldSupplier) {
+            @NonNull RawFoldingFeatureProducer rawFoldSupplier,
+            @NonNull DeviceStateManager deviceStateManager) {
         mRawFoldSupplier = rawFoldSupplier;
         String[] deviceStatePosturePairs = context.getResources()
                 .getStringArray(R.array.config_device_state_postures);
+        boolean isHalfOpenedSupported = false;
         for (String deviceStatePosturePair : deviceStatePosturePairs) {
             String[] deviceStatePostureMapping = deviceStatePosturePair.split(":");
             if (deviceStatePostureMapping.length != 2) {
@@ -128,12 +133,13 @@
                 }
                 continue;
             }
-
+            isHalfOpenedSupported = isHalfOpenedSupported
+                    || posture == CommonFoldingFeature.COMMON_STATE_HALF_OPENED;
             mDeviceStateToPostureMap.put(deviceState, posture);
         }
-
+        mIsHalfOpenedSupported = isHalfOpenedSupported;
         if (mDeviceStateToPostureMap.size() > 0) {
-            Objects.requireNonNull(context.getSystemService(DeviceStateManager.class))
+            Objects.requireNonNull(deviceStateManager)
                     .registerCallback(context.getMainExecutor(), mDeviceStateCallback);
         }
     }
@@ -188,6 +194,31 @@
     }
 
     /**
+     * Returns a {@link List} of all the {@link CommonFoldingFeature} with the state set to
+     * {@link CommonFoldingFeature#COMMON_STATE_UNKNOWN}. This method parses a {@link String} so a
+     * caller should consider caching the value or the derived value.
+     */
+    @NonNull
+    public List<CommonFoldingFeature> getFoldsWithUnknownState() {
+        Optional<String> optionalFoldingFeatureString = mRawFoldSupplier.getCurrentData();
+
+        if (optionalFoldingFeatureString.isPresent()) {
+            return CommonFoldingFeature.parseListFromString(
+                    optionalFoldingFeatureString.get(), CommonFoldingFeature.COMMON_STATE_UNKNOWN
+            );
+        }
+        return Collections.emptyList();
+    }
+
+
+    /**
+     * Returns {@code true} if the device supports half-opened mode, {@code false} otherwise.
+     */
+    public boolean isHalfOpenedSupported() {
+        return mIsHalfOpenedSupported;
+    }
+
+    /**
      * Adds the data to the storeFeaturesConsumer when the data is ready.
      * @param storeFeaturesConsumer a consumer to collect the data when it is first available.
      */
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
index 29cf054..6714263 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
@@ -20,6 +20,7 @@
 import android.app.ActivityThread;
 import android.app.Application;
 import android.content.Context;
+import android.hardware.devicestate.DeviceStateManager;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
@@ -64,6 +65,11 @@
     }
 
     @NonNull
+    private DeviceStateManager getDeviceStateManager() {
+        return Objects.requireNonNull(getApplication().getSystemService(DeviceStateManager.class));
+    }
+
+    @NonNull
     private DeviceStateManagerFoldingFeatureProducer getFoldingFeatureProducer() {
         if (mFoldingFeatureProducer == null) {
             synchronized (mLock) {
@@ -73,7 +79,7 @@
                             new RawFoldingFeatureProducer(context);
                     mFoldingFeatureProducer =
                             new DeviceStateManagerFoldingFeatureProducer(context,
-                                    foldingFeatureProducer);
+                                    foldingFeatureProducer, getDeviceStateManager());
                 }
             }
         }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
index 08b7bb8..39cface 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
@@ -201,7 +201,7 @@
             return null;
         }
         return new SplitInfo(primaryActivityStack, secondaryActivityStack,
-                mCurrentSplitAttributes, mToken);
+                mCurrentSplitAttributes, SplitInfo.Token.createFromBinder(mToken));
     }
 
     static boolean shouldFinishPrimaryWithSecondary(@NonNull SplitRule splitRule) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index b2e5b75..1abda42 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -35,6 +35,7 @@
 import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED;
 import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED;
 
+import static androidx.window.extensions.embedding.ActivityEmbeddingOptionsProperties.KEY_ACTIVITY_STACK_TOKEN;
 import static androidx.window.extensions.embedding.ActivityEmbeddingOptionsProperties.KEY_OVERLAY_TAG;
 import static androidx.window.extensions.embedding.SplitContainer.getFinishPrimaryWithSecondaryBehavior;
 import static androidx.window.extensions.embedding.SplitContainer.getFinishSecondaryWithPrimaryBehavior;
@@ -55,6 +56,7 @@
 import android.app.ActivityThread;
 import android.app.Application;
 import android.app.Instrumentation;
+import android.app.servertransaction.ClientTransactionListenerController;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -72,6 +74,7 @@
 import android.util.Size;
 import android.util.SparseArray;
 import android.view.WindowMetrics;
+import android.window.ActivityWindowInfo;
 import android.window.TaskFragmentAnimationParams;
 import android.window.TaskFragmentInfo;
 import android.window.TaskFragmentOperation;
@@ -101,6 +104,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.Executor;
+import java.util.function.BiConsumer;
 
 /**
  * Main controller class that manages split states and presentation.
@@ -111,10 +115,6 @@
     static final boolean ENABLE_SHELL_TRANSITIONS =
             SystemProperties.getBoolean("persist.wm.debug.shell_transit", true);
 
-    // TODO(b/295993745): remove after prebuilt library is updated.
-    private static final String KEY_ACTIVITY_STACK_TOKEN =
-            "androidx.window.extensions.embedding.ActivityStackToken";
-
     @VisibleForTesting
     @GuardedBy("mLock")
     final SplitPresenter mPresenter;
@@ -180,6 +180,20 @@
 
     private final List<ActivityStack> mLastReportedActivityStacks = new ArrayList<>();
 
+    /** WM Jetpack set callback for {@link EmbeddedActivityWindowInfo}. */
+    @GuardedBy("mLock")
+    @Nullable
+    private Pair<Executor, Consumer<EmbeddedActivityWindowInfo>>
+            mEmbeddedActivityWindowInfoCallback;
+
+    /** Listener registered to {@link ClientTransactionListenerController}. */
+    @GuardedBy("mLock")
+    @Nullable
+    private final BiConsumer<IBinder, ActivityWindowInfo> mActivityWindowInfoListener =
+            Flags.activityWindowInfoFlag()
+                    ? this::onActivityWindowInfoChanged
+                    : null;
+
     private final Handler mHandler;
     final Object mLock = new Object();
     private final ActivityStartMonitor mActivityStartMonitor;
@@ -553,7 +567,7 @@
     }
 
     @Override
-    public void updateActivityStackAttributes(@NonNull IBinder activityStackToken,
+    public void updateActivityStackAttributes(@NonNull ActivityStack.Token activityStackToken,
                                               @NonNull ActivityStackAttributes attributes) {
         if (!Flags.activityEmbeddingOverlayPresentationFlag()) {
             return;
@@ -562,7 +576,7 @@
         Objects.requireNonNull(attributes);
 
         synchronized (mLock) {
-            final TaskFragmentContainer container = getContainer(activityStackToken);
+            final TaskFragmentContainer container = getContainer(activityStackToken.getRawToken());
             if (container == null) {
                 Log.w(TAG, "Cannot find TaskFragmentContainer for token:" + activityStackToken);
                 return;
@@ -582,13 +596,14 @@
 
     @Override
     @Nullable
-    public ParentContainerInfo getParentContainerInfo(@NonNull IBinder activityStackToken) {
+    public ParentContainerInfo getParentContainerInfo(
+            @NonNull ActivityStack.Token activityStackToken) {
         if (!Flags.activityEmbeddingOverlayPresentationFlag()) {
             return null;
         }
         Objects.requireNonNull(activityStackToken);
         synchronized (mLock) {
-            final TaskFragmentContainer container = getContainer(activityStackToken);
+            final TaskFragmentContainer container = getContainer(activityStackToken.getRawToken());
             if (container == null) {
                 return null;
             }
@@ -600,7 +615,7 @@
 
     @Override
     @Nullable
-    public IBinder getActivityStackToken(@NonNull String tag) {
+    public ActivityStack.Token getActivityStackToken(@NonNull String tag) {
         if (!Flags.activityEmbeddingOverlayPresentationFlag()) {
             return null;
         }
@@ -611,7 +626,8 @@
             if (taskFragmentContainer == null) {
                 return null;
             }
-            return taskFragmentContainer.getTaskFragmentToken();
+            return ActivityStack.Token.createFromBinder(taskFragmentContainer
+                    .getTaskFragmentToken());
         }
     }
 
@@ -2456,6 +2472,13 @@
     }
 
     @VisibleForTesting
+    @Nullable
+    ActivityThread.ActivityClientRecord getActivityClientRecord(@NonNull Activity activity) {
+        return ActivityThread.currentActivityThread()
+                .getActivityClient(activity.getActivityToken());
+    }
+
+    @VisibleForTesting
     ActivityStartMonitor getActivityStartMonitor() {
         return mActivityStartMonitor;
     }
@@ -2468,8 +2491,7 @@
     @VisibleForTesting
     @Nullable
     IBinder getTaskFragmentTokenFromActivityClientRecord(@NonNull Activity activity) {
-        final ActivityThread.ActivityClientRecord record = ActivityThread.currentActivityThread()
-                .getActivityClient(activity.getActivityToken());
+        final ActivityThread.ActivityClientRecord record = getActivityClientRecord(activity);
         return record != null ? record.mTaskFragmentToken : null;
     }
 
@@ -2760,8 +2782,10 @@
             // TODO(b/232042367): Consolidate the activity create handling so that we can handle
             // cross-process the same as normal.
 
-            IBinder activityStackToken = options.getBinder(KEY_ACTIVITY_STACK_TOKEN);
-            if (activityStackToken != null) {
+            final Bundle bundle = options.getBundle(KEY_ACTIVITY_STACK_TOKEN);
+            if (bundle != null) {
+                final IBinder activityStackToken = ActivityStack.Token.readFromBundle(bundle)
+                        .getRawToken();
                 // Put activityStack token to #KEY_LAUNCH_TASK_FRAGMENT_TOKEN to launch the activity
                 // into the taskFragment associated with the token.
                 options.putBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN, activityStackToken);
@@ -2864,11 +2888,112 @@
      */
     @Override
     public boolean isActivityEmbedded(@NonNull Activity activity) {
+        Objects.requireNonNull(activity);
         synchronized (mLock) {
+            if (Flags.activityWindowInfoFlag()) {
+                final ActivityWindowInfo activityWindowInfo = getActivityWindowInfo(activity);
+                return activityWindowInfo != null && activityWindowInfo.isEmbedded();
+            }
             return mPresenter.isActivityEmbedded(activity.getActivityToken());
         }
     }
 
+    @Override
+    public void setEmbeddedActivityWindowInfoCallback(@NonNull Executor executor,
+            @NonNull Consumer<EmbeddedActivityWindowInfo> callback) {
+        if (!Flags.activityWindowInfoFlag()) {
+            return;
+        }
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+        synchronized (mLock) {
+            if (mEmbeddedActivityWindowInfoCallback == null) {
+                ClientTransactionListenerController.getInstance()
+                        .registerActivityWindowInfoChangedListener(getActivityWindowInfoListener());
+            }
+            mEmbeddedActivityWindowInfoCallback = new Pair<>(executor, callback);
+        }
+    }
+
+    @Override
+    public void clearEmbeddedActivityWindowInfoCallback() {
+        if (!Flags.activityWindowInfoFlag()) {
+            return;
+        }
+        synchronized (mLock) {
+            if (mEmbeddedActivityWindowInfoCallback == null) {
+                return;
+            }
+            mEmbeddedActivityWindowInfoCallback = null;
+            ClientTransactionListenerController.getInstance()
+                    .unregisterActivityWindowInfoChangedListener(getActivityWindowInfoListener());
+        }
+    }
+
+    @VisibleForTesting
+    @GuardedBy("mLock")
+    @Nullable
+    BiConsumer<IBinder, ActivityWindowInfo> getActivityWindowInfoListener() {
+        return mActivityWindowInfoListener;
+    }
+
+    @Nullable
+    @Override
+    public EmbeddedActivityWindowInfo getEmbeddedActivityWindowInfo(@NonNull Activity activity) {
+        if (!Flags.activityWindowInfoFlag()) {
+            return null;
+        }
+        synchronized (mLock) {
+            final ActivityWindowInfo activityWindowInfo = getActivityWindowInfo(activity);
+            return activityWindowInfo != null
+                    ? translateActivityWindowInfo(activity, activityWindowInfo)
+                    : null;
+        }
+    }
+
+    @VisibleForTesting
+    void onActivityWindowInfoChanged(@NonNull IBinder activityToken,
+            @NonNull ActivityWindowInfo activityWindowInfo) {
+        synchronized (mLock) {
+            if (mEmbeddedActivityWindowInfoCallback == null) {
+                return;
+            }
+            final Executor executor = mEmbeddedActivityWindowInfoCallback.first;
+            final Consumer<EmbeddedActivityWindowInfo> callback =
+                    mEmbeddedActivityWindowInfoCallback.second;
+
+            final Activity activity = getActivity(activityToken);
+            if (activity == null) {
+                return;
+            }
+            final EmbeddedActivityWindowInfo info = translateActivityWindowInfo(
+                    activity, activityWindowInfo);
+
+            executor.execute(() -> callback.accept(info));
+        }
+    }
+
+    @Nullable
+    private ActivityWindowInfo getActivityWindowInfo(@NonNull Activity activity) {
+        if (activity.isFinishing()) {
+            return null;
+        }
+        final ActivityThread.ActivityClientRecord record = getActivityClientRecord(activity);
+        return record != null ? record.getActivityWindowInfo() : null;
+    }
+
+    @NonNull
+    private static EmbeddedActivityWindowInfo translateActivityWindowInfo(
+            @NonNull Activity activity, @NonNull ActivityWindowInfo activityWindowInfo) {
+        final boolean isEmbedded = activityWindowInfo.isEmbedded();
+        final Rect activityBounds = new Rect(activity.getResources().getConfiguration()
+                .windowConfiguration.getBounds());
+        final Rect taskBounds = new Rect(activityWindowInfo.getTaskBounds());
+        final Rect activityStackBounds = new Rect(activityWindowInfo.getTaskFragmentBounds());
+        return new EmbeddedActivityWindowInfo(activity, isEmbedded, activityBounds, taskBounds,
+                activityStackBounds);
+    }
+
     /**
      * If the two rules have the same presentation, and the calculated {@link SplitAttributes}
      * matches the {@link SplitAttributes} of {@link SplitContainer}, we can reuse the same
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 2f2da8c..b53b9c5 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -387,7 +387,7 @@
 
         // Sets the dim area when the two TaskFragments are adjacent.
         final boolean dimOnTask = !isStacked
-                && splitAttributes.getWindowAttributes().getDimArea() == DIM_AREA_ON_TASK
+                && splitAttributes.getWindowAttributes().getDimAreaBehavior() == DIM_AREA_ON_TASK
                 && Flags.fullscreenDimFlag();
         setTaskFragmentDimOnTask(wct, primaryContainer.getTaskFragmentToken(), dimOnTask);
         setTaskFragmentDimOnTask(wct, secondaryContainer.getTaskFragmentToken(), dimOnTask);
@@ -590,7 +590,7 @@
         final boolean isFillParent = relativeBounds.isEmpty();
         final boolean isIsolatedNavigated = !isFillParent && container.isOverlay();
         final boolean dimOnTask = !isFillParent
-                && attributes.getWindowAttributes().getDimArea() == DIM_AREA_ON_TASK
+                && attributes.getWindowAttributes().getDimAreaBehavior() == DIM_AREA_ON_TASK
                 && Flags.fullscreenDimFlag();
         final IBinder fragmentToken = container.getTaskFragmentToken();
 
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 6fe8e50..a6bf99d 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -367,7 +367,8 @@
         if (activities == null) {
             return null;
         }
-        return new ActivityStack(activities, isEmpty(), mToken, mOverlayTag);
+        return new ActivityStack(activities, isEmpty(),
+                ActivityStack.Token.createFromBinder(mToken), mOverlayTag);
     }
 
     /** Adds the activity that will be reparented to this container. */
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/DisplayFoldFeatureUtil.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/DisplayFoldFeatureUtil.java
new file mode 100644
index 0000000..a0f481a
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/DisplayFoldFeatureUtil.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.layout;
+
+import androidx.window.common.CommonFoldingFeature;
+import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Util functions for working with {@link androidx.window.extensions.layout.DisplayFoldFeature}.
+ */
+public class DisplayFoldFeatureUtil {
+
+    private DisplayFoldFeatureUtil() {}
+
+    private static DisplayFoldFeature create(CommonFoldingFeature foldingFeature,
+            boolean isHalfOpenedSupported) {
+        final int foldType;
+        if (foldingFeature.getType() == CommonFoldingFeature.COMMON_TYPE_HINGE) {
+            foldType = DisplayFoldFeature.TYPE_HINGE;
+        } else {
+            foldType = DisplayFoldFeature.TYPE_SCREEN_FOLD_IN;
+        }
+        DisplayFoldFeature.Builder featureBuilder = new DisplayFoldFeature.Builder(foldType);
+
+        if (isHalfOpenedSupported) {
+            featureBuilder.addProperty(DisplayFoldFeature.FOLD_PROPERTY_SUPPORTS_HALF_OPENED);
+        }
+        return featureBuilder.build();
+    }
+
+    /**
+     * Returns the list of supported {@link DisplayFeature} calculated from the
+     * {@link DeviceStateManagerFoldingFeatureProducer}.
+     */
+    public static List<DisplayFoldFeature> extractDisplayFoldFeatures(
+            DeviceStateManagerFoldingFeatureProducer producer) {
+        List<DisplayFoldFeature> foldFeatures = new ArrayList<>();
+        List<CommonFoldingFeature> folds = producer.getFoldsWithUnknownState();
+
+        final boolean isHalfOpenedSupported = producer.isHalfOpenedSupported();
+        for (CommonFoldingFeature fold : folds) {
+            foldFeatures.add(DisplayFoldFeatureUtil.create(fold, isHalfOpenedSupported));
+        }
+        return foldFeatures;
+    }
+}
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 6e704f3..4fd11c4 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
@@ -45,7 +45,6 @@
 import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
 import androidx.window.common.EmptyLifecycleCallbacksAdapter;
 import androidx.window.extensions.core.util.function.Consumer;
-import androidx.window.util.DataProducer;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -56,10 +55,6 @@
 /**
  * Reference implementation of androidx.window.extensions.layout OEM interface for use with
  * WindowManager Jetpack.
- *
- * NOTE: This version is a work in progress and under active development. It MUST NOT be used in
- * production builds since the interface can still change before reaching stable version.
- * Please refer to {@link androidx.window.sidecar.SampleSidecarImpl} instead.
  */
 public class WindowLayoutComponentImpl implements WindowLayoutComponent {
     private static final String TAG = WindowLayoutComponentImpl.class.getSimpleName();
@@ -71,7 +66,7 @@
             new ArrayMap<>();
 
     @GuardedBy("mLock")
-    private final DataProducer<List<CommonFoldingFeature>> mFoldingFeatureProducer;
+    private final DeviceStateManagerFoldingFeatureProducer mFoldingFeatureProducer;
 
     @GuardedBy("mLock")
     private final List<CommonFoldingFeature> mLastReportedFoldingFeatures = new ArrayList<>();
@@ -87,12 +82,17 @@
     private final RawConfigurationChangedListener mRawConfigurationChangedListener =
             new RawConfigurationChangedListener();
 
+    private final SupportedWindowFeatures mSupportedWindowFeatures;
+
     public WindowLayoutComponentImpl(@NonNull Context context,
             @NonNull DeviceStateManagerFoldingFeatureProducer foldingFeatureProducer) {
         ((Application) context.getApplicationContext())
                 .registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged());
         mFoldingFeatureProducer = foldingFeatureProducer;
         mFoldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
+        final List<DisplayFoldFeature> displayFoldFeatures =
+                DisplayFoldFeatureUtil.extractDisplayFoldFeatures(mFoldingFeatureProducer);
+        mSupportedWindowFeatures = new SupportedWindowFeatures.Builder(displayFoldFeatures).build();
     }
 
     /**
@@ -283,6 +283,15 @@
         }
     }
 
+    /**
+     * Returns the {@link SupportedWindowFeatures} for the device. This list does not change over
+     * time.
+     */
+    @NonNull
+    public SupportedWindowFeatures getSupportedWindowFeatures() {
+        return mSupportedWindowFeatures;
+    }
+
     /** @see #getWindowLayoutInfo(Context, List) */
     private WindowLayoutInfo getWindowLayoutInfo(int displayId,
             @NonNull WindowConfiguration windowConfiguration,
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
index a836e05..56c3bce 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
@@ -17,6 +17,7 @@
 package androidx.window.sidecar;
 
 import static android.view.Display.DEFAULT_DISPLAY;
+
 import static androidx.window.util.ExtensionHelper.rotateRectToDisplayRotation;
 import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect;
 
@@ -25,6 +26,7 @@
 import android.app.Application;
 import android.content.Context;
 import android.graphics.Rect;
+import android.hardware.devicestate.DeviceStateManager;
 import android.os.Bundle;
 import android.os.IBinder;
 
@@ -49,10 +51,11 @@
     SampleSidecarImpl(Context context) {
         ((Application) context.getApplicationContext())
                 .registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged());
-        BaseDataProducer<String> settingsFeatureProducer = new RawFoldingFeatureProducer(context);
+        RawFoldingFeatureProducer settingsFeatureProducer = new RawFoldingFeatureProducer(context);
         BaseDataProducer<List<CommonFoldingFeature>> foldingFeatureProducer =
                 new DeviceStateManagerFoldingFeatureProducer(context,
-                        settingsFeatureProducer);
+                        settingsFeatureProducer,
+                        context.getSystemService(DeviceStateManager.class));
 
         foldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
     }
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
index 34d43ad..28fbadb 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
@@ -399,7 +399,8 @@
                         new ActivityStackAttributes.Builder().build()));
 
         assertThrows(NullPointerException.class, () ->
-                mSplitController.updateActivityStackAttributes(new Binder(), null));
+                mSplitController.updateActivityStackAttributes(
+                        ActivityStack.Token.createFromBinder(new Binder()), null));
 
         verify(mSplitPresenter, never()).applyActivityStackAttributes(any(), any(), any(), any());
     }
@@ -408,7 +409,8 @@
     public void testUpdateActivityStackAttributes_nullContainer_earlyReturn() {
         final TaskFragmentContainer container = mSplitController.newContainer(mActivity,
                 mActivity.getTaskId());
-        mSplitController.updateActivityStackAttributes(container.getTaskFragmentToken(),
+        mSplitController.updateActivityStackAttributes(
+                ActivityStack.Token.createFromBinder(container.getTaskFragmentToken()),
                 new ActivityStackAttributes.Builder().build());
 
         verify(mSplitPresenter, never()).applyActivityStackAttributes(any(), any(), any(), any());
@@ -418,7 +420,8 @@
     public void testUpdateActivityStackAttributes_notOverlay_earlyReturn() {
         final TaskFragmentContainer container = createMockTaskFragmentContainer(mActivity);
 
-        mSplitController.updateActivityStackAttributes(container.getTaskFragmentToken(),
+        mSplitController.updateActivityStackAttributes(
+                ActivityStack.Token.createFromBinder(container.getTaskFragmentToken()),
                 new ActivityStackAttributes.Builder().build());
 
         verify(mSplitPresenter, never()).applyActivityStackAttributes(any(), any(), any(), any());
@@ -431,7 +434,8 @@
         final ActivityStackAttributes attrs = new ActivityStackAttributes.Builder().build();
         final IBinder token = container.getTaskFragmentToken();
 
-        mSplitController.updateActivityStackAttributes(token, attrs);
+        mSplitController.updateActivityStackAttributes(ActivityStack.Token.createFromBinder(token),
+                attrs);
 
         verify(mSplitPresenter).applyActivityStackAttributes(any(), eq(container), eq(attrs),
                 any());
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index b60943a..bdeeb73 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -72,6 +72,8 @@
 import android.annotation.NonNull;
 import android.app.Activity;
 import android.app.ActivityOptions;
+import android.app.ActivityThread;
+import android.app.servertransaction.ClientTransactionListenerController;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -83,9 +85,11 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.util.ArraySet;
 import android.view.WindowInsets;
 import android.view.WindowMetrics;
+import android.window.ActivityWindowInfo;
 import android.window.TaskFragmentInfo;
 import android.window.TaskFragmentOrganizer;
 import android.window.TaskFragmentParentInfo;
@@ -99,7 +103,10 @@
 import androidx.window.extensions.layout.WindowLayoutComponentImpl;
 import androidx.window.extensions.layout.WindowLayoutInfo;
 
+import com.android.window.flags.Flags;
+
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -110,6 +117,8 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
 /**
@@ -127,6 +136,9 @@
     private static final Intent PLACEHOLDER_INTENT = new Intent().setComponent(
             new ComponentName("test", "placeholder"));
 
+    @Rule
+    public final SetFlagsRule mSetFlagRule = new SetFlagsRule();
+
     private Activity mActivity;
     @Mock
     private Resources mActivityResources;
@@ -138,6 +150,13 @@
     private Handler mHandler;
     @Mock
     private WindowLayoutComponentImpl mWindowLayoutComponent;
+    @Mock
+    private ActivityWindowInfo mActivityWindowInfo;
+    @Mock
+    private BiConsumer<IBinder, ActivityWindowInfo> mActivityWindowInfoListener;
+    @Mock
+    private androidx.window.extensions.core.util.function.Consumer<EmbeddedActivityWindowInfo>
+            mEmbeddedActivityWindowInfoCallback;
 
     private SplitController mSplitController;
     private SplitPresenter mSplitPresenter;
@@ -1437,7 +1456,7 @@
     @Test
     public void testUpdateSplitAttributes_nullParams_throwException() {
         assertThrows(NullPointerException.class,
-                () -> mSplitController.updateSplitAttributes(null, SPLIT_ATTRIBUTES));
+                () -> mSplitController.updateSplitAttributes((IBinder) null, SPLIT_ATTRIBUTES));
 
         final SplitContainer splitContainer = mock(SplitContainer.class);
         final IBinder token = new Binder();
@@ -1529,6 +1548,73 @@
                 .getTopNonFinishingActivity(), secondaryActivity);
     }
 
+    @Test
+    public void testIsActivityEmbedded() {
+        mSetFlagRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG);
+
+        assertFalse(mSplitController.isActivityEmbedded(mActivity));
+
+        doReturn(true).when(mActivityWindowInfo).isEmbedded();
+
+        assertTrue(mSplitController.isActivityEmbedded(mActivity));
+    }
+
+    @Test
+    public void testGetEmbeddedActivityWindowInfo() {
+        mSetFlagRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG);
+
+        final boolean isEmbedded = true;
+        final Rect activityBounds = mActivity.getResources().getConfiguration().windowConfiguration
+                .getBounds();
+        final Rect taskBounds = new Rect(0, 0, 1000, 2000);
+        final Rect activityStackBounds = new Rect(0, 0, 500, 2000);
+        doReturn(isEmbedded).when(mActivityWindowInfo).isEmbedded();
+        doReturn(taskBounds).when(mActivityWindowInfo).getTaskBounds();
+        doReturn(activityStackBounds).when(mActivityWindowInfo).getTaskFragmentBounds();
+
+        final EmbeddedActivityWindowInfo expected = new EmbeddedActivityWindowInfo(mActivity,
+                isEmbedded, activityBounds, taskBounds, activityStackBounds);
+        assertEquals(expected, mSplitController.getEmbeddedActivityWindowInfo(mActivity));
+    }
+
+    @Test
+    public void testSetEmbeddedActivityWindowInfoCallback() {
+        mSetFlagRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG);
+
+        final ClientTransactionListenerController controller = ClientTransactionListenerController
+                .getInstance();
+        spyOn(controller);
+        doNothing().when(controller).registerActivityWindowInfoChangedListener(any());
+        doReturn(mActivityWindowInfoListener).when(mSplitController)
+                .getActivityWindowInfoListener();
+        final Executor executor = Runnable::run;
+
+        // Register to ClientTransactionListenerController
+        mSplitController.setEmbeddedActivityWindowInfoCallback(executor,
+                mEmbeddedActivityWindowInfoCallback);
+
+        verify(controller).registerActivityWindowInfoChangedListener(mActivityWindowInfoListener);
+        verify(mEmbeddedActivityWindowInfoCallback, never()).accept(any());
+
+        // Test onActivityWindowInfoChanged triggered.
+        mSplitController.onActivityWindowInfoChanged(mActivity.getActivityToken(),
+                mActivityWindowInfo);
+
+        verify(mEmbeddedActivityWindowInfoCallback).accept(any());
+
+        // Unregister to ClientTransactionListenerController
+        mSplitController.clearEmbeddedActivityWindowInfoCallback();
+
+        verify(controller).unregisterActivityWindowInfoChangedListener(mActivityWindowInfoListener);
+
+        // Test onActivityWindowInfoChanged triggered as no-op after clear callback.
+        clearInvocations(mEmbeddedActivityWindowInfoCallback);
+        mSplitController.onActivityWindowInfoChanged(mActivity.getActivityToken(),
+                mActivityWindowInfo);
+
+        verify(mEmbeddedActivityWindowInfoCallback, never()).accept(any());
+    }
+
     /** Creates a mock activity in the organizer process. */
     private Activity createMockActivity() {
         return createMockActivity(TASK_ID);
@@ -1537,13 +1623,17 @@
     /** Creates a mock activity in the organizer process. */
     private Activity createMockActivity(int taskId) {
         final Activity activity = mock(Activity.class);
+        final ActivityThread.ActivityClientRecord activityClientRecord =
+                mock(ActivityThread.ActivityClientRecord.class);
         doReturn(mActivityResources).when(activity).getResources();
         final IBinder activityToken = new Binder();
         doReturn(activityToken).when(activity).getActivityToken();
         doReturn(activity).when(mSplitController).getActivity(activityToken);
+        doReturn(activityClientRecord).when(mSplitController).getActivityClientRecord(activity);
         doReturn(taskId).when(activity).getTaskId();
         doReturn(new ActivityInfo()).when(activity).getActivityInfo();
         doReturn(DEFAULT_DISPLAY).when(activity).getDisplayId();
+        doReturn(mActivityWindowInfo).when(activityClientRecord).getActivityWindowInfo();
         return activity;
     }
 
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index d66c925..8829d1b 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -82,16 +82,18 @@
 genrule {
     name: "wm_shell_protolog_src",
     srcs: [
+        ":protolog-impl",
         ":wm_shell_protolog-groups",
         ":wm_shell-sources",
     ],
     tools: ["protologtool"],
     cmd: "$(location protologtool) transform-protolog-calls " +
         "--protolog-class com.android.internal.protolog.common.ProtoLog " +
-        "--protolog-impl-class com.android.wm.shell.protolog.ShellProtoLogImpl " +
-        "--protolog-cache-class com.android.wm.shell.protolog.ShellProtoLogCache " +
         "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
         "--loggroups-jar $(location :wm_shell_protolog-groups) " +
+        "--viewer-config-file-path /system_ext/etc/wmshell.protolog.pb " +
+        "--legacy-viewer-config-file-path /system_ext/etc/wmshell.protolog.json.gz " +
+        "--legacy-output-file-path /data/misc/wmtrace/shell_log.winscope " +
         "--output-srcjar $(out) " +
         "$(locations :wm_shell-sources)",
     out: ["wm_shell_protolog.srcjar"],
@@ -108,12 +110,30 @@
         "--protolog-class com.android.internal.protolog.common.ProtoLog " +
         "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
         "--loggroups-jar $(location :wm_shell_protolog-groups) " +
-        "--viewer-conf $(out) " +
+        "--viewer-config-type json " +
+        "--viewer-config $(out) " +
         "$(locations :wm_shell-sources)",
     out: ["wm_shell_protolog.json"],
 }
 
 genrule {
+    name: "gen-wmshell.protolog.pb",
+    srcs: [
+        ":wm_shell_protolog-groups",
+        ":wm_shell-sources",
+    ],
+    tools: ["protologtool"],
+    cmd: "$(location protologtool) generate-viewer-config " +
+        "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+        "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
+        "--loggroups-jar $(location :wm_shell_protolog-groups) " +
+        "--viewer-config-type proto " +
+        "--viewer-config $(out) " +
+        "$(locations :wm_shell-sources)",
+    out: ["wmshell.protolog.pb"],
+}
+
+genrule {
     name: "protolog.json.gz",
     srcs: [":generate-wm_shell_protolog.json"],
     out: ["wmshell.protolog.json.gz"],
@@ -127,6 +147,13 @@
     filename_from_src: true,
 }
 
+prebuilt_etc {
+    name: "wmshell.protolog.pb",
+    system_ext_specific: true,
+    src: ":gen-wmshell.protolog.pb",
+    filename_from_src: true,
+}
+
 // End ProtoLog
 
 java_library {
@@ -185,76 +212,3 @@
     plugins: ["dagger2-compiler"],
     use_resource_processor: true,
 }
-
-android_app {
-    name: "WindowManagerShellRobolectric",
-    platform_apis: true,
-    static_libs: [
-        "WindowManager-Shell",
-    ],
-    manifest: "multivalentTests/AndroidManifestRobolectric.xml",
-    use_resource_processor: true,
-}
-
-android_robolectric_test {
-    name: "WMShellRobolectricTests",
-    instrumentation_for: "WindowManagerShellRobolectric",
-    upstream: true,
-    java_resource_dirs: [
-        "multivalentTests/robolectric/config",
-    ],
-    srcs: [
-        "multivalentTests/src/**/*.kt",
-    ],
-    // TODO(b/323188766): Include BubbleStackViewTest once the robolectric issue is fixed.
-    exclude_srcs: ["multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt"],
-    static_libs: [
-        "junit",
-        "androidx.test.runner",
-        "androidx.test.rules",
-        "androidx.test.ext.junit",
-        "mockito-robolectric-prebuilt",
-        "mockito-kotlin2",
-        "truth",
-    ],
-}
-
-android_test {
-    name: "WMShellMultivalentTestsOnDevice",
-    srcs: [
-        "multivalentTests/src/**/*.kt",
-    ],
-    static_libs: [
-        "WindowManager-Shell",
-        "junit",
-        "androidx.test.runner",
-        "androidx.test.rules",
-        "androidx.test.ext.junit",
-        "frameworks-base-testutils",
-        "mockito-kotlin2",
-        "mockito-target-extended-minus-junit4",
-        "truth",
-        "platform-test-annotations",
-        "platform-test-rules",
-    ],
-    libs: [
-        "android.test.base",
-        "android.test.runner",
-    ],
-    jni_libs: [
-        "libdexmakerjvmtiagent",
-        "libstaticjvmtiagent",
-    ],
-    kotlincflags: ["-Xjvm-default=all"],
-    optimize: {
-        enabled: false,
-    },
-    test_suites: ["device-tests"],
-    platform_apis: true,
-    certificate: "platform",
-    aaptflags: [
-        "--extra-packages",
-        "com.android.wm.shell",
-    ],
-    manifest: "multivalentTests/AndroidManifest.xml",
-}
diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
index 0967f4e..b61dda4 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -8,14 +8,6 @@
 }
 
 flag {
-    name: "enable_desktop_windowing"
-    namespace: "multitasking"
-    description: "Enables desktop windowing"
-    bug: "304778354"
-    is_fixed_read_only: true
-}
-
-flag {
     name: "enable_split_contextual"
     namespace: "multitasking"
     description: "Enables invoking split contextually"
diff --git a/libs/WindowManager/Shell/multivalentTests/Android.bp b/libs/WindowManager/Shell/multivalentTests/Android.bp
new file mode 100644
index 0000000..1686d0d
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentTests/Android.bp
@@ -0,0 +1,97 @@
+// 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
+    default_applicable_licenses: ["frameworks_base_license"],
+    default_team: "trendy_team_multitasking_windowing",
+}
+
+android_app {
+    name: "WindowManagerShellRobolectric",
+    platform_apis: true,
+    static_libs: [
+        "WindowManager-Shell",
+    ],
+    manifest: "AndroidManifestRobolectric.xml",
+    use_resource_processor: true,
+}
+
+android_robolectric_test {
+    name: "WMShellRobolectricTests",
+    instrumentation_for: "WindowManagerShellRobolectric",
+    upstream: true,
+    java_resource_dirs: [
+        "robolectric/config",
+    ],
+    srcs: [
+        "src/**/*.kt",
+    ],
+    // TODO(b/323188766): Include BubbleStackViewTest once the robolectric issue is fixed.
+    exclude_srcs: ["src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt"],
+    static_libs: [
+        "junit",
+        "androidx.test.runner",
+        "androidx.test.rules",
+        "androidx.test.ext.junit",
+        "mockito-robolectric-prebuilt",
+        "mockito-kotlin2",
+        "truth",
+    ],
+    auto_gen_config: true,
+}
+
+android_test {
+    name: "WMShellMultivalentTestsOnDevice",
+    srcs: [
+        "src/**/*.kt",
+    ],
+    static_libs: [
+        "WindowManager-Shell",
+        "junit",
+        "androidx.test.runner",
+        "androidx.test.rules",
+        "androidx.test.ext.junit",
+        "frameworks-base-testutils",
+        "mockito-kotlin2",
+        "mockito-target-extended-minus-junit4",
+        "truth",
+        "platform-test-annotations",
+        "platform-test-rules",
+    ],
+    libs: [
+        "android.test.base",
+        "android.test.runner",
+    ],
+    jni_libs: [
+        "libdexmakerjvmtiagent",
+        "libstaticjvmtiagent",
+    ],
+    kotlincflags: ["-Xjvm-default=all"],
+    optimize: {
+        enabled: false,
+    },
+    test_suites: ["device-tests"],
+    platform_apis: true,
+    certificate: "platform",
+    aaptflags: [
+        "--extra-packages",
+        "com.android.wm.shell",
+    ],
+    manifest: "AndroidManifest.xml",
+}
diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_header_ic_close.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_header_ic_close.xml
new file mode 100644
index 0000000..ff49edb
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_header_ic_close.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
+</vector>
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
index d1b1af3..a5605a7 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
@@ -16,6 +16,7 @@
   -->
 <com.android.wm.shell.windowdecor.WindowDecorLinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/desktop_mode_caption"
     android:layout_width="match_parent"
@@ -27,17 +28,20 @@
         android:id="@+id/open_menu_button"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
+        android:tint="?androidprv:attr/materialColorOnSurface"
+        android:background="?android:selectableItemBackground"
         android:orientation="horizontal"
         android:clickable="true"
         android:focusable="true"
-        android:paddingStart="6dp"
-        android:paddingEnd="8dp">
+        android:paddingStart="12dp">
         <ImageView
             android:id="@+id/application_icon"
             android:layout_width="@dimen/desktop_mode_caption_icon_radius"
             android:layout_height="@dimen/desktop_mode_caption_icon_radius"
             android:layout_gravity="center_vertical"
-            android:contentDescription="@string/app_icon_text" />
+            android:contentDescription="@string/app_icon_text"
+            android:layout_marginStart="6dp"
+            android:scaleType="centerCrop"/>
 
         <TextView
             android:id="@+id/application_name"
@@ -50,8 +54,7 @@
             android:lineHeight="20dp"
             android:layout_gravity="center_vertical"
             android:layout_weight="1"
-            android:paddingStart="8dp"
-            android:paddingEnd="8dp"
+            android:layout_marginStart="8dp"
             tools:text="Gmail"/>
 
         <ImageButton
@@ -64,6 +67,7 @@
             android:scaleType="fitCenter"
             android:clickable="false"
             android:focusable="false"
+            android:layout_marginHorizontal="8dp"
             android:layout_gravity="center_vertical"/>
 
     </LinearLayout>
@@ -78,17 +82,21 @@
         android:id="@+id/maximize_button_view"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="end"/>
+        android:layout_gravity="end"
+        android:clickable="true"
+        android:focusable="true" />
 
     <ImageButton
         android:id="@+id/close_window"
-        android:layout_width="40dp"
+        android:layout_width="44dp"
         android:layout_height="40dp"
-        android:padding="4dp"
+        android:paddingHorizontal="10dp"
+        android:paddingVertical="8dp"
         android:layout_marginEnd="8dp"
+        android:tint="?androidprv:attr/materialColorOnSurface"
+        android:background="?android:selectableItemBackgroundBorderless"
         android:contentDescription="@string/close_button_text"
-        android:src="@drawable/decor_close_button_dark"
-        android:scaleType="fitCenter"
-        android:gravity="end"
-        android:background="@null"/>
+        android:src="@drawable/desktop_mode_header_ic_close"
+        android:scaleType="centerCrop"
+        android:gravity="end"/>
 </com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml b/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml
index bb6efce..e0057fe 100644
--- a/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml
+++ b/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml
@@ -14,7 +14,8 @@
   ~ limitations under the License.
   -->
 
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
     <ProgressBar
         android:id="@+id/progress_bar"
         style="?android:attr/progressBarStyleHorizontal"
@@ -30,7 +31,8 @@
         android:layout_height="40dp"
         android:padding="9dp"
         android:contentDescription="@string/maximize_button_text"
+        android:tint="?androidprv:attr/materialColorOnSurface"
+        android:background="?android:selectableItemBackgroundBorderless"
         android:src="@drawable/decor_desktop_mode_maximize_button_dark"
-        android:scaleType="fitCenter"
-        android:background="@drawable/rounded_button"/>
+        android:scaleType="fitCenter" />
 </merge>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index 8baaf2f..a541c59 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -145,4 +145,7 @@
 
     <!-- Whether CompatUIController is enabled -->
     <bool name="config_enableCompatUIController">true</bool>
+
+    <!-- Whether pointer pilfer is required to start back animation. -->
+    <bool name="config_backAnimationRequiresPointerPilfer">true</bool>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index cbfa74e..7dd3961 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -101,6 +101,10 @@
     <dimen name="split_divider_bar_width">10dp</dimen>
     <dimen name="split_divider_corner_size">42dp</dimen>
 
+    <!-- The distance from the edge of the screen to invoke splitscreen when the user is dragging
+         an intent that can be launched into split. -->
+    <dimen name="drag_launchable_intent_edge_margin">48dp</dimen>
+
     <!-- One-Handed Mode -->
     <!-- Threshold for dragging distance to enable one-handed mode -->
     <dimen name="gestures_onehanded_drag_threshold">20dp</dimen>
@@ -430,15 +434,22 @@
     <!-- (32 dp buttons + 10dp margins) * 3 buttons-->
     <dimen name="caption_right_buttons_width">126dp</dimen>
 
-    <!-- 2 buttons * 48dp button size. -->
-    <dimen name="desktop_mode_right_edge_buttons_width">96dp</dimen>
+    <!-- 2 buttons * 44dp button size + 16dp total margins. -->
+    <dimen name="desktop_mode_right_edge_buttons_width">104dp</dimen>
 
     <!-- 22dp padding + 24dp app icon + 16dp expand button.
          Text varies in size, we will calculate that width separately. -->
     <dimen name="desktop_mode_app_details_width_minus_text">62dp</dimen>
 
-    <!-- 22dp padding + 24dp app icon + 16dp expand button + 86dp text (max) -->
-    <dimen name="desktop_mode_app_details_max_width">148dp</dimen>
+    <!-- When custom headers are requested, this is the width of the left-aligned region that is
+         taken up by caption elements and extra margins. The customizable region starts at the
+         end of this area. -->
+    <dimen name="desktop_mode_customizable_caption_margin_start">84dp</dimen>
+
+    <!-- When custom headers are requested, this is the width of the right-aligned region that is
+         taken up by caption elements and extra margins. The customizable region ends at the
+         start of this area. -->
+    <dimen name="desktop_mode_customizable_caption_margin_end">152dp</dimen>
 
     <!-- The width of the maximize menu in desktop mode. -->
     <dimen name="desktop_mode_maximize_menu_width">287dp</dimen>
@@ -486,7 +497,7 @@
     <dimen name="desktop_mode_handle_menu_corner_radius">26dp</dimen>
 
     <!-- The radius of the caption menu icon. -->
-    <dimen name="desktop_mode_caption_icon_radius">28dp</dimen>
+    <dimen name="desktop_mode_caption_icon_radius">24dp</dimen>
 
     <!-- The radius of the caption menu shadow. -->
     <dimen name="desktop_mode_handle_menu_shadow_radius">2dp</dimen>
@@ -499,10 +510,6 @@
     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>
-
     <!-- The width of the area where a desktop task will transition to fullscreen. -->
     <dimen name="desktop_mode_fullscreen_from_desktop_width">80dp</dimen>
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
index 88525aa..ef9bf00 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
@@ -16,7 +16,10 @@
 
 package com.android.wm.shell;
 
-import com.android.wm.shell.protolog.ShellProtoLogImpl;
+import com.android.internal.protolog.LegacyProtoLogImpl;
+import com.android.internal.protolog.common.ILogger;
+import com.android.internal.protolog.common.IProtoLog;
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellInit;
 
@@ -24,19 +27,19 @@
 import java.util.Arrays;
 
 /**
- * Controls the {@link ShellProtoLogImpl} in WMShell via adb shell commands.
+ * Controls the {@link ProtoLog} in WMShell via adb shell commands.
  *
  * Use with {@code adb shell dumpsys activity service SystemUIService WMShell protolog ...}.
  */
 public class ProtoLogController implements ShellCommandHandler.ShellCommandActionHandler {
     private final ShellCommandHandler mShellCommandHandler;
-    private final ShellProtoLogImpl mShellProtoLog;
+    private final IProtoLog mShellProtoLog;
 
     public ProtoLogController(ShellInit shellInit,
             ShellCommandHandler shellCommandHandler) {
         shellInit.addInitCallback(this::onInit, this);
         mShellCommandHandler = shellCommandHandler;
-        mShellProtoLog = ShellProtoLogImpl.getSingleInstance();
+        mShellProtoLog = ProtoLog.getSingleInstance();
     }
 
     void onInit() {
@@ -45,22 +48,35 @@
 
     @Override
     public boolean onShellCommand(String[] args, PrintWriter pw) {
+        final ILogger logger = pw::println;
         switch (args[0]) {
             case "status": {
-                pw.println(mShellProtoLog.getStatus());
+                if (android.tracing.Flags.perfettoProtologTracing()) {
+                    pw.println("(Deprecated) legacy command. Use Perfetto commands instead.");
+                    return false;
+                }
+                ((LegacyProtoLogImpl) mShellProtoLog).getStatus();
                 return true;
             }
             case "start": {
-                mShellProtoLog.startProtoLog(pw);
+                if (android.tracing.Flags.perfettoProtologTracing()) {
+                    pw.println("(Deprecated) legacy command. Use Perfetto commands instead.");
+                    return false;
+                }
+                ((LegacyProtoLogImpl) mShellProtoLog).startProtoLog(pw);
                 return true;
             }
             case "stop": {
-                mShellProtoLog.stopProtoLog(pw, true /* writeToFile */);
+                if (android.tracing.Flags.perfettoProtologTracing()) {
+                    pw.println("(Deprecated) legacy command. Use Perfetto commands instead.");
+                    return false;
+                }
+                ((LegacyProtoLogImpl) mShellProtoLog).stopProtoLog(pw, true);
                 return true;
             }
             case "enable-text": {
                 String[] groups = Arrays.copyOfRange(args, 1, args.length);
-                int result = mShellProtoLog.startTextLogging(groups, pw);
+                int result = mShellProtoLog.startLoggingToLogcat(groups, logger);
                 if (result == 0) {
                     pw.println("Starting logging on groups: " + Arrays.toString(groups));
                     return true;
@@ -69,7 +85,7 @@
             }
             case "disable-text": {
                 String[] groups = Arrays.copyOfRange(args, 1, args.length);
-                int result = mShellProtoLog.stopTextLogging(groups, pw);
+                int result = mShellProtoLog.stopLoggingToLogcat(groups, logger);
                 if (result == 0) {
                     pw.println("Stopping logging on groups: " + Arrays.toString(groups));
                     return true;
@@ -78,19 +94,23 @@
             }
             case "enable": {
                 String[] groups = Arrays.copyOfRange(args, 1, args.length);
-                return mShellProtoLog.startTextLogging(groups, pw) == 0;
+                return mShellProtoLog.startLoggingToLogcat(groups, logger) == 0;
             }
             case "disable": {
                 String[] groups = Arrays.copyOfRange(args, 1, args.length);
-                return mShellProtoLog.stopTextLogging(groups, pw) == 0;
+                return mShellProtoLog.stopLoggingToLogcat(groups, logger) == 0;
             }
             case "save-for-bugreport": {
+                if (android.tracing.Flags.perfettoProtologTracing()) {
+                    pw.println("(Deprecated) legacy command");
+                    return false;
+                }
                 if (!mShellProtoLog.isProtoEnabled()) {
                     pw.println("Logging to proto is not enabled for WMShell.");
                     return false;
                 }
-                mShellProtoLog.stopProtoLog(pw, true /* writeToFile */);
-                mShellProtoLog.startProtoLog(pw);
+                ((LegacyProtoLogImpl) mShellProtoLog).stopProtoLog(pw, true /* writeToFile */);
+                ((LegacyProtoLogImpl) mShellProtoLog).startProtoLog(pw);
                 return true;
             }
             default: {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 2606fb6..9bd8531 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -64,6 +64,7 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.LatencyTracker;
 import com.android.internal.view.AppearanceRegion;
+import com.android.wm.shell.R;
 import com.android.wm.shell.animation.FlingAnimationUtils;
 import com.android.wm.shell.common.ExternalInterfaceBinder;
 import com.android.wm.shell.common.RemoteCallable;
@@ -115,6 +116,7 @@
     private boolean mShouldStartOnNextMoveEvent = false;
     private boolean mOnBackStartDispatched = false;
     private boolean mPointerPilfered = false;
+    private final boolean mRequirePointerPilfer;
 
     private final FlingAnimationUtils mFlingAnimationUtils;
 
@@ -220,6 +222,8 @@
         mActivityTaskManager = activityTaskManager;
         mContext = context;
         mContentResolver = contentResolver;
+        mRequirePointerPilfer =
+                context.getResources().getBoolean(R.bool.config_backAnimationRequiresPointerPilfer);
         mBgHandler = bgHandler;
         shellInit.addInitCallback(this::onInit, this);
         mAnimationBackground = backAnimationBackground;
@@ -560,7 +564,9 @@
     private void tryDispatchOnBackStarted(
             IOnBackInvokedCallback callback,
             BackMotionEvent backEvent) {
-        if (mOnBackStartDispatched || callback == null || !mPointerPilfered) {
+        if (mOnBackStartDispatched
+                || callback == null
+                || (!mPointerPilfered && mRequirePointerPilfer)) {
             return;
         }
         dispatchOnBackStarted(callback, backEvent);
@@ -1006,6 +1012,8 @@
         pw.println(prefix + "  mBackGestureStarted=" + mBackGestureStarted);
         pw.println(prefix + "  mPostCommitAnimationInProgress=" + mPostCommitAnimationInProgress);
         pw.println(prefix + "  mShouldStartOnNextMoveEvent=" + mShouldStartOnNextMoveEvent);
+        pw.println(prefix + "  mPointerPilfered=" + mPointerPilfered);
+        pw.println(prefix + "  mRequirePointerPilfer=" + mRequirePointerPilfer);
         pw.println(prefix + "  mCurrentTracker state:");
         mCurrentTracker.dump(pw, prefix + "    ");
         pw.println(prefix + "  mQueuedTracker state:");
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 15350fb..96aaf02 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
@@ -1799,11 +1799,12 @@
         @Override
         public void removeBubble(Bubble removedBubble) {
             if (mLayerView != null) {
-                mLayerView.removeBubble(removedBubble);
-                if (!mBubbleData.hasBubbles() && !isStackExpanded()) {
-                    mLayerView.setVisibility(INVISIBLE);
-                    removeFromWindowManagerMaybe();
-                }
+                mLayerView.removeBubble(removedBubble, () -> {
+                    if (!mBubbleData.hasBubbles() && !isStackExpanded()) {
+                        mLayerView.setVisibility(INVISIBLE);
+                        removeFromWindowManagerMaybe();
+                    }
+                });
             }
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index 78a41f7..42799d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -242,13 +242,17 @@
     }
 
     /** Removes the given {@code bubble}. */
-    public void removeBubble(Bubble bubble) {
+    public void removeBubble(Bubble bubble, Runnable endAction) {
+        Runnable cleanUp = () -> {
+            bubble.cleanupViews();
+            endAction.run();
+        };
         if (mBubbleData.getBubbles().isEmpty()) {
             // we're removing the last bubble. collapse the expanded view and cleanup bubble views
             // at the end.
-            collapse(bubble::cleanupViews);
+            collapse(cleanUp);
         } else {
-            bubble.cleanupViews();
+            cleanUp.run();
         }
     }
 
@@ -264,6 +268,9 @@
      */
     public void collapse(@Nullable Runnable endAction) {
         if (!mIsExpanded) {
+            if (endAction != null) {
+                endAction.run();
+            }
             return;
         }
         mIsExpanded = false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index 2ea4316..ad01d0f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -20,12 +20,12 @@
 import static android.view.EventLogTags.IMF_IME_REMOTE_ANIM_END;
 import static android.view.EventLogTags.IMF_IME_REMOTE_ANIM_START;
 import static android.view.inputmethod.ImeTracker.DEBUG_IME_VISIBILITY;
-import static android.view.inputmethod.ImeTracker.TOKEN_NONE;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.res.Configuration;
@@ -51,6 +51,7 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.wm.shell.sysui.ShellInit;
 
 import java.util.ArrayList;
@@ -122,7 +123,8 @@
         }
         if (mDisplayController.getDisplayLayout(displayId).rotation()
                 != pd.mRotation && isImeShowing(displayId)) {
-            pd.startAnimation(true, false /* forceRestart */, null /* statsToken */);
+            pd.startAnimation(true, false /* forceRestart */,
+                    SoftInputShowHideReason.DISPLAY_CONFIGURATION_CHANGED);
         }
     }
 
@@ -257,7 +259,8 @@
             mInsetsState.set(insetsState, true /* copySources */);
             if (mImeShowing && !Objects.equals(oldFrame, newFrame) && newSourceVisible) {
                 if (DEBUG) Slog.d(TAG, "insetsChanged when IME showing, restart animation");
-                startAnimation(mImeShowing, true /* forceRestart */, null /* statsToken */);
+                startAnimation(mImeShowing, true /* forceRestart */,
+                        SoftInputShowHideReason.DISPLAY_INSETS_CHANGED);
             }
         }
 
@@ -291,7 +294,8 @@
                     final boolean positionChanged =
                             !imeSourceControl.getSurfacePosition().equals(lastSurfacePosition);
                     if (positionChanged) {
-                        startAnimation(mImeShowing, true /* forceRestart */, null /* statsToken */);
+                        startAnimation(mImeShowing, true /* forceRestart */,
+                                SoftInputShowHideReason.DISPLAY_CONTROLS_CHANGED);
                     }
                 } else {
                     if (!haveSameLeash(mImeSourceControl, imeSourceControl)) {
@@ -384,7 +388,20 @@
         }
 
         private void startAnimation(final boolean show, final boolean forceRestart,
-                @Nullable ImeTracker.Token statsToken) {
+                @SoftInputShowHideReason int reason) {
+            final var imeSource = mInsetsState.peekSource(InsetsSource.ID_IME);
+            if (imeSource == null || mImeSourceControl == null) {
+                return;
+            }
+            final var statsToken = ImeTracker.forLogging().onStart(
+                    show ? ImeTracker.TYPE_SHOW : ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_WM_SHELL,
+                    reason, false /* fromUser */);
+
+            startAnimation(show, forceRestart, statsToken);
+        }
+
+        private void startAnimation(final boolean show, final boolean forceRestart,
+                @NonNull final ImeTracker.Token statsToken) {
             final InsetsSource imeSource = mInsetsState.peekSource(InsetsSource.ID_IME);
             if (imeSource == null || mImeSourceControl == null) {
                 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_WM_ANIMATION_CREATE);
@@ -458,7 +475,7 @@
             ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_WM_ANIMATION_CREATE);
             mAnimation.addListener(new AnimatorListenerAdapter() {
                 private boolean mCancelled = false;
-                @Nullable
+                @NonNull
                 private final ImeTracker.Token mStatsToken = statsToken;
 
                 @Override
@@ -484,7 +501,7 @@
                     }
                     if (DEBUG_IME_VISIBILITY) {
                         EventLog.writeEvent(IMF_IME_REMOTE_ANIM_START,
-                                statsToken != null ? statsToken.getTag() : TOKEN_NONE,
+                                mStatsToken != null ? mStatsToken.getTag() : ImeTracker.TOKEN_NONE,
                                 mDisplayId, mAnimationDirection, alpha, startY , endY,
                                 Objects.toString(mImeSourceControl.getLeash()),
                                 Objects.toString(mImeSourceControl.getInsetsHint()),
@@ -500,7 +517,8 @@
                     mCancelled = true;
                     if (DEBUG_IME_VISIBILITY) {
                         EventLog.writeEvent(IMF_IME_REMOTE_ANIM_CANCEL,
-                                statsToken != null ? statsToken.getTag() : TOKEN_NONE, mDisplayId,
+                                mStatsToken != null ? mStatsToken.getTag() : ImeTracker.TOKEN_NONE,
+                                mDisplayId,
                                 Objects.toString(mImeSourceControl.getInsetsHint()));
                     }
                 }
@@ -528,7 +546,7 @@
                     }
                     if (DEBUG_IME_VISIBILITY) {
                         EventLog.writeEvent(IMF_IME_REMOTE_ANIM_END,
-                                statsToken != null ? statsToken.getTag() : TOKEN_NONE,
+                                mStatsToken != null ? mStatsToken.getTag() : ImeTracker.TOKEN_NONE,
                                 mDisplayId, mAnimationDirection, endY,
                                 Objects.toString(mImeSourceControl.getLeash()),
                                 Objects.toString(mImeSourceControl.getInsetsHint()),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
index 9bdda14..ca06024 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
@@ -277,8 +277,7 @@
          *
          * @param types {@link InsetsType} to show
          * @param fromIme true if this request originated from IME (InputMethodService).
-         * @param statsToken the token tracking the current IME show request
-         *                   or {@code null} otherwise.
+         * @param statsToken the token tracking the current IME request or {@code null} otherwise.
          */
         default void showInsets(@InsetsType int types, boolean fromIme,
                 @Nullable ImeTracker.Token statsToken) {}
@@ -288,8 +287,7 @@
          *
          * @param types {@link InsetsType} to hide
          * @param fromIme true if this request originated from IME (InputMethodService).
-         * @param statsToken the token tracking the current IME hide request
-         *                   or {@code null} otherwise.
+         * @param statsToken the token tracking the current IME request or {@code null} otherwise.
          */
         default void hideInsets(@InsetsType int types, boolean fromIme,
                 @Nullable ImeTracker.Token statsToken) {}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
index b57e2d2..b87c2f6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
@@ -228,6 +228,14 @@
         mExpandedMovementBounds.set(bounds);
     }
 
+    /** Updates the min and max sizes based on the size spec and aspect ratio. */
+    public void updateMinMaxSize(float aspectRatio) {
+        final Size minSize = mSizeSpecSource.getMinSize(aspectRatio);
+        mMinSize.set(minSize.getWidth(), minSize.getHeight());
+        final Size maxSize = mSizeSpecSource.getMaxSize(aspectRatio);
+        mMaxSize.set(maxSize.getWidth(), maxSize.getHeight());
+    }
+
     /** Sets the max possible size for resize. */
     public void setMaxSize(int width, int height) {
         mMaxSize.set(width, height);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index f801b0d..a87116e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -75,7 +75,6 @@
     private SurfaceControlViewHost mViewHost;
     private DividerHandleView mHandle;
     private DividerRoundedCorner mCorners;
-    private View mBackground;
     private int mTouchElevation;
 
     private VelocityTracker mVelocityTracker;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/OWNERS
index 7237d2b..37ccd15 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/OWNERS
@@ -1,2 +1,4 @@
 # WM shell sub-modules splitscreen owner
 chenghsiuchang@google.com
+jeremysim@google.com
+peanutbutter@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index 2b10377..dae62ac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -138,8 +138,10 @@
         mViewHost.setView(rootLayout, lp);
     }
 
-    /** Releases the surfaces for split decor. */
-    public void release(SurfaceControl.Transaction t) {
+    /**
+     * Cancels any currently running animations.
+     */
+    public void cancelRunningAnimations() {
         if (mFadeAnimator != null) {
             if (mFadeAnimator.isRunning()) {
                 mFadeAnimator.cancel();
@@ -152,6 +154,11 @@
             }
             mScreenshotAnimator = null;
         }
+    }
+
+    /** Releases the surfaces for split decor. */
+    public void release(SurfaceControl.Transaction t) {
+        cancelRunningAnimations();
         if (mViewHost != null) {
             mViewHost.release();
             mViewHost = null;
@@ -277,7 +284,7 @@
                 }
 
                 @Override
-                public void onAnimationEnd(@androidx.annotation.NonNull Animator animation) {
+                public void onAnimationEnd(@NonNull Animator animation) {
                     mRunningAnimationCount--;
                     animT.remove(mScreenshot);
                     animT.apply();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 53caddb..6b2d544 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -510,16 +510,18 @@
         }
     }
 
-    /** Updates divide position and split bounds base on the ratio within root bounds. */
+    /**
+     * Updates divide position and split bounds base on the ratio within root bounds. Falls back
+     * to middle position if the provided SnapTarget is not supported.
+     */
     public void setDivideRatio(@PersistentSnapPosition int snapPosition) {
         final DividerSnapAlgorithm.SnapTarget snapTarget = mDividerSnapAlgorithm.findSnapTarget(
                 snapPosition);
 
-        if (snapTarget == null) {
-            throw new IllegalArgumentException("No SnapTarget for position " + snapPosition);
-        }
-
-        setDividePosition(snapTarget.position, false /* applyLayoutChange */);
+        setDividePosition(snapTarget != null
+                ? snapTarget.position
+                : mDividerSnapAlgorithm.getMiddleTarget().position,
+                false /* applyLayoutChange */);
     }
 
     /** Resets divider position. */
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 f757e1c..fb3c35b 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
@@ -201,9 +201,11 @@
     @Provides
     static WindowDecorViewModel provideWindowDecorViewModel(
             Context context,
+            @ShellMainThread ShellExecutor mainExecutor,
             @ShellMainThread Handler mainHandler,
             @ShellMainThread Choreographer mainChoreographer,
             ShellInit shellInit,
+            IWindowManager windowManager,
             ShellCommandHandler shellCommandHandler,
             ShellTaskOrganizer taskOrganizer,
             DisplayController displayController,
@@ -216,10 +218,12 @@
         if (DesktopModeStatus.isEnabled()) {
             return new DesktopModeWindowDecorViewModel(
                     context,
+                    mainExecutor,
                     mainHandler,
                     mainChoreographer,
                     shellInit,
                     shellCommandHandler,
+                    windowManager,
                     taskOrganizer,
                     displayController,
                     shellController,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
index 8305fa6..1071d72 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
@@ -51,4 +51,6 @@
     /** Called when requested to go to desktop mode from the current focused app. */
     void enterDesktop(int displayId);
 
+    /** Called when requested to go to fullscreen from the current focused desktop app. */
+    void moveFocusedTaskToFullscreen(int displayId);
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
new file mode 100644
index 0000000..95d4714
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode
+
+import com.android.internal.util.FrameworkStatsLog
+import com.android.wm.shell.protolog.ShellProtoLogGroup
+import com.android.wm.shell.util.KtProtoLog
+
+/**
+ * Event logger for logging desktop mode session events
+ */
+class DesktopModeEventLogger {
+    /**
+     * Logs the enter of desktop mode having session id [sessionId] and the reason [enterReason] for
+     * entering desktop mode
+     */
+    fun logSessionEnter(sessionId: Int, enterReason: EnterReason) {
+        KtProtoLog.v(
+            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            "DesktopModeLogger: Logging session enter, session: %s reason: %s",
+            sessionId, enterReason.name
+        )
+        FrameworkStatsLog.write(DESKTOP_MODE_ATOM_ID,
+            /* event */ FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__ENTER,
+            /* enterReason */ enterReason.reason,
+            /* exitReason */ 0,
+            /* session_id */ sessionId)
+    }
+
+    /**
+     * Logs the exit of desktop mode having session id [sessionId] and the reason [exitReason] for
+     * exiting desktop mode
+     */
+    fun logSessionExit(sessionId: Int, exitReason: ExitReason) {
+        KtProtoLog.v(
+            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            "DesktopModeLogger: Logging session exit, session: %s reason: %s",
+            sessionId, exitReason.name
+        )
+        FrameworkStatsLog.write(DESKTOP_MODE_ATOM_ID,
+            /* event */ FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__EXIT,
+            /* enterReason */ 0,
+            /* exitReason */ exitReason.reason,
+            /* session_id */ sessionId)
+    }
+
+    /**
+     * Logs that the task with update [taskUpdate] was added in the desktop mode session having
+     * session id [sessionId]
+     */
+    fun logTaskAdded(sessionId: Int, taskUpdate: TaskUpdate) {
+        KtProtoLog.v(
+            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            "DesktopModeLogger: Logging task added, session: %s taskId: %s",
+            sessionId, taskUpdate.instanceId
+        )
+        FrameworkStatsLog.write(DESKTOP_MODE_TASK_UPDATE_ATOM_ID,
+            /* task_event */
+            FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_ADDED,
+            /* instance_id */
+            taskUpdate.instanceId,
+            /* uid */
+            taskUpdate.uid,
+            /* task_height */
+            taskUpdate.taskHeight,
+            /* task_width */
+            taskUpdate.taskWidth,
+            /* task_x */
+            taskUpdate.taskX,
+            /* task_y */
+            taskUpdate.taskY,
+            /* session_id */
+            sessionId)
+    }
+
+    /**
+     * Logs that the task with update [taskUpdate] was removed in the desktop mode session having
+     * session id [sessionId]
+     */
+    fun logTaskRemoved(sessionId: Int, taskUpdate: TaskUpdate) {
+        KtProtoLog.v(
+            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            "DesktopModeLogger: Logging task remove, session: %s taskId: %s",
+            sessionId, taskUpdate.instanceId
+        )
+        FrameworkStatsLog.write(DESKTOP_MODE_TASK_UPDATE_ATOM_ID,
+            /* task_event */
+            FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_REMOVED,
+            /* instance_id */
+            taskUpdate.instanceId,
+            /* uid */
+            taskUpdate.uid,
+            /* task_height */
+            taskUpdate.taskHeight,
+            /* task_width */
+            taskUpdate.taskWidth,
+            /* task_x */
+            taskUpdate.taskX,
+            /* task_y */
+            taskUpdate.taskY,
+            /* session_id */
+            sessionId)
+    }
+
+    /**
+     * Logs that the task with update [taskUpdate] had it's info changed in the desktop mode session
+     * having session id [sessionId]
+     */
+    fun logTaskInfoChanged(sessionId: Int, taskUpdate: TaskUpdate) {
+        KtProtoLog.v(
+            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            "DesktopModeLogger: Logging task info changed, session: %s taskId: %s",
+            sessionId, taskUpdate.instanceId
+        )
+        FrameworkStatsLog.write(DESKTOP_MODE_TASK_UPDATE_ATOM_ID,
+            /* task_event */
+            FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED,
+            /* instance_id */
+            taskUpdate.instanceId,
+            /* uid */
+            taskUpdate.uid,
+            /* task_height */
+            taskUpdate.taskHeight,
+            /* task_width */
+            taskUpdate.taskWidth,
+            /* task_x */
+            taskUpdate.taskX,
+            /* task_y */
+            taskUpdate.taskY,
+            /* session_id */
+            sessionId)
+    }
+
+    companion object {
+        data class TaskUpdate(
+            val instanceId: Int,
+            val uid: Int,
+            val taskHeight: Int = Int.MIN_VALUE,
+            val taskWidth: Int = Int.MIN_VALUE,
+            val taskX: Int = Int.MIN_VALUE,
+            val taskY: Int = Int.MIN_VALUE,
+        )
+
+        /**
+         * Enum EnterReason mapped to the EnterReason definition in
+         * stats/atoms/desktopmode/desktopmode_extensions_atoms.proto
+         */
+        enum class EnterReason(val reason: Int) {
+            UNKNOWN_ENTER(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__UNKNOWN_ENTER
+            ),
+            OVERVIEW(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__OVERVIEW
+            ),
+            APP_HANDLE_DRAG(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__APP_HANDLE_DRAG
+            ),
+            APP_HANDLE_MENU_BUTTON(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__APP_HANDLE_MENU_BUTTON
+            ),
+            APP_FREEFORM_INTENT(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__APP_FREEFORM_INTENT
+            ),
+            KEYBOARD_SHORTCUT_ENTER(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__KEYBOARD_SHORTCUT_ENTER
+            ),
+            SCREEN_ON(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__SCREEN_ON
+            );
+        }
+
+        /**
+         * Enum ExitReason mapped to the ExitReason definition in
+         * stats/atoms/desktopmode/desktopmode_extensions_atoms.proto
+         */
+        enum class ExitReason(val reason: Int) {
+            UNKNOWN_EXIT(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__UNKNOWN_EXIT
+            ),
+            DRAG_TO_EXIT(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__DRAG_TO_EXIT
+            ),
+            APP_HANDLE_MENU_BUTTON_EXIT(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__APP_HANDLE_MENU_BUTTON_EXIT
+            ),
+            KEYBOARD_SHORTCUT_EXIT(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__KEYBOARD_SHORTCUT_EXIT
+            ),
+            RETURN_HOME_OR_OVERVIEW(
+                FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME
+            ),
+            TASK_FINISHED(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__TASK_FINISHED
+            ),
+            SCREEN_OFF(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__SCREEN_OFF
+            )
+        }
+
+        private const val DESKTOP_MODE_ATOM_ID = FrameworkStatsLog.DESKTOP_MODE_UI_CHANGED
+        private const val DESKTOP_MODE_TASK_UPDATE_ATOM_ID =
+            FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE
+    }
+}
\ No newline at end of file
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 88949b2a..22ba708 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
@@ -18,21 +18,13 @@
 
 import android.os.SystemProperties;
 
-import com.android.wm.shell.Flags;
+import com.android.window.flags.Flags;
 
 /**
  * Constants for desktop mode feature
  */
 public class DesktopModeStatus {
 
-    private static final boolean ENABLE_DESKTOP_WINDOWING = Flags.enableDesktopWindowing();
-
-    /**
-     * 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);
-
     /**
      * Flag to indicate whether task resizing is veiled.
      */
@@ -75,16 +67,10 @@
             "persist.wm.debug.desktop_use_rounded_corners", true);
 
     /**
-     * Return {@code true} is desktop windowing proto 2 is enabled
+     * Return {@code true} if desktop windowing is enabled
      */
     public static boolean isEnabled() {
-        // Check for aconfig flag first
-        if (ENABLE_DESKTOP_WINDOWING) {
-            return true;
-        }
-        // Fall back to sysprop flag
-        // TODO(b/304778354): remove sysprop once desktop aconfig flag supports dynamic overriding
-        return IS_PROTO2_ENABLED;
+        return Flags.enableDesktopWindowingMode();
     }
 
     /**
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 4053418..fb0ed15 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
@@ -22,8 +22,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 
-import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.RectEvaluator;
@@ -100,6 +98,7 @@
      * Based on the coordinates of the current drag event, determine which indicator type we should
      * display, including no visible indicator.
      */
+    @NonNull
     IndicatorType updateIndicatorType(PointF inputCoordinates, int windowingMode) {
         final DisplayLayout layout = mDisplayController.getDisplayLayout(mTaskInfo.displayId);
         // If we are in freeform, we don't want a visible indicator in the "freeform" drag zone.
@@ -138,18 +137,18 @@
     Region calculateFullscreenRegion(DisplayLayout layout,
             @WindowConfiguration.WindowingMode int windowingMode, int captionHeight) {
         final Region region = new Region();
-        int edgeTransitionHeight = mContext.getResources().getDimensionPixelSize(
-                com.android.wm.shell.R.dimen.desktop_mode_transition_area_height);
+        int transitionHeight = windowingMode == WINDOWING_MODE_FREEFORM
+                ? 2 * layout.stableInsets().top
+                : mContext.getResources().getDimensionPixelSize(
+                        com.android.wm.shell.R.dimen.desktop_mode_fullscreen_from_desktop_height);
         // A thin, short Rect at the top of the screen.
         if (windowingMode == WINDOWING_MODE_FREEFORM) {
             int fromFreeformWidth = mContext.getResources().getDimensionPixelSize(
                     com.android.wm.shell.R.dimen.desktop_mode_fullscreen_from_desktop_width);
-            int fromFreeformHeight = mContext.getResources().getDimensionPixelSize(
-                    com.android.wm.shell.R.dimen.desktop_mode_fullscreen_from_desktop_height);
             region.union(new Rect((layout.width() / 2) - (fromFreeformWidth / 2),
                     -captionHeight,
                     (layout.width() / 2) + (fromFreeformWidth / 2),
-                    fromFreeformHeight));
+                    transitionHeight));
         }
         // A screen-wide, shorter Rect if the task is in fullscreen or split.
         if (windowingMode == WINDOWING_MODE_FULLSCREEN
@@ -157,7 +156,7 @@
             region.union(new Rect(0,
                     -captionHeight,
                     layout.width(),
-                    edgeTransitionHeight));
+                    transitionHeight));
         }
         return region;
     }
@@ -389,7 +388,8 @@
                             layout.width() - padding,
                             layout.height() - padding);
                 case TO_DESKTOP_INDICATOR:
-                    final float adjustmentPercentage = 1f - FINAL_FREEFORM_SCALE;
+                    final float adjustmentPercentage = 1f
+                            - DesktopTasksController.DESKTOP_MODE_INITIAL_BOUNDS_SCALE;
                     return new Rect((int) (adjustmentPercentage * layout.width() / 2),
                             (int) (adjustmentPercentage * layout.height() / 2),
                             (int) (layout.width() - (adjustmentPercentage * layout.width() / 2)),
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 98f9988..654409f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.desktopmode
 
-import android.app.ActivityManager
 import android.app.ActivityManager.RunningTaskInfo
 import android.app.ActivityOptions
 import android.app.PendingIntent
@@ -35,7 +34,6 @@
 import android.graphics.Region
 import android.os.IBinder
 import android.os.SystemProperties
-import android.util.DisplayMetrics.DENSITY_DEFAULT
 import android.view.Display.DEFAULT_DISPLAY
 import android.view.SurfaceControl
 import android.view.WindowManager.TRANSIT_CHANGE
@@ -51,6 +49,7 @@
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
 import com.android.wm.shell.ShellTaskOrganizer
 import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayLayout
 import com.android.wm.shell.common.ExecutorUtils
 import com.android.wm.shell.common.ExternalInterfaceBinder
 import com.android.wm.shell.common.LaunchAdjacentController
@@ -63,12 +62,10 @@
 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.DragToDesktopTransitionHandler.DragToDesktopStateListener
 import com.android.wm.shell.draganddrop.DragAndDropController
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
-import com.android.wm.shell.recents.RecentTasksController
 import com.android.wm.shell.recents.RecentsTransitionHandler
 import com.android.wm.shell.recents.RecentsTransitionStateListener
 import com.android.wm.shell.splitscreen.SplitScreenController
@@ -85,7 +82,6 @@
 import java.io.PrintWriter
 import java.util.concurrent.Executor
 import java.util.function.Consumer
-import java.util.function.Function
 
 /** Handles moving tasks in and out of desktop */
 class DesktopTasksController(
@@ -144,7 +140,7 @@
 
     private val transitionAreaHeight
         get() = context.resources.getDimensionPixelSize(
-                com.android.wm.shell.R.dimen.desktop_mode_transition_area_height
+                com.android.wm.shell.R.dimen.desktop_mode_fullscreen_from_desktop_height
         )
 
     private val transitionAreaWidth
@@ -384,6 +380,18 @@
         }
     }
 
+    /** Enter fullscreen by moving the focused freeform task in given `displayId` to fullscreen. */
+    fun enterFullscreen(displayId: Int) {
+        if (DesktopModeStatus.isEnabled()) {
+            shellTaskOrganizer
+                    .getRunningTasks(displayId)
+                    .find { taskInfo ->
+                        taskInfo.isFocused && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM
+                    }
+                    ?.let { moveToFullscreenWithAnimation(it, it.positionInParent) }
+        }
+    }
+
     /** Move a desktop app to split screen. */
     fun moveToSplit(task: RunningTaskInfo) {
         KtProtoLog.v(
@@ -408,23 +416,9 @@
                     splitScreenController.getStageOfTask(taskInfo.taskId),
                     EXIT_REASON_DESKTOP_MODE
             )
-            getOtherSplitTask(taskInfo.taskId)?.let { otherTaskInfo ->
-                wct.removeTask(otherTaskInfo.token)
-            }
         }
     }
 
-    private fun getOtherSplitTask(taskId: Int): RunningTaskInfo? {
-        val remainingTaskPosition: Int =
-                if (splitScreenController.getSplitPosition(taskId)
-                        == SPLIT_POSITION_BOTTOM_OR_RIGHT) {
-                    SPLIT_POSITION_TOP_OR_LEFT
-                } else {
-                    SPLIT_POSITION_BOTTOM_OR_RIGHT
-                }
-        return splitScreenController.getTaskInfo(remainingTaskPosition)
-    }
-
     /**
      * The second part of the animated drag to desktop transition, called after
      * [startDragToDesktop].
@@ -551,11 +545,7 @@
         if (taskInfo.configuration.windowConfiguration.bounds == stableBounds) {
             // The desktop task is currently occupying the whole stable bounds, toggle to the
             // default bounds.
-            getDefaultDesktopTaskBounds(
-                density = taskInfo.configuration.densityDpi.toFloat() / DENSITY_DEFAULT,
-                stableBounds = stableBounds,
-                outBounds = destinationBounds
-            )
+            getDefaultDesktopTaskBounds(displayLayout, destinationBounds)
         } else {
             // Toggle to the stable bounds.
             destinationBounds.set(stableBounds)
@@ -575,30 +565,7 @@
      * @param position the portion of the screen (RIGHT or LEFT) we want to snap the task to.
      */
     fun snapToHalfScreen(taskInfo: RunningTaskInfo, position: SnapPosition) {
-        val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return
-
-        val stableBounds = Rect()
-        displayLayout.getStableBounds(stableBounds)
-
-        val destinationWidth = stableBounds.width() / 2
-        val destinationBounds = when (position) {
-            SnapPosition.LEFT -> {
-                Rect(
-                        stableBounds.left,
-                        stableBounds.top,
-                        stableBounds.left + destinationWidth,
-                        stableBounds.bottom
-                )
-            }
-            SnapPosition.RIGHT -> {
-                Rect(
-                        stableBounds.right - destinationWidth,
-                        stableBounds.top,
-                        stableBounds.right,
-                        stableBounds.bottom
-                )
-            }
-        }
+        val destinationBounds = getSnapBounds(taskInfo, position)
 
         if (destinationBounds == taskInfo.configuration.windowConfiguration.bounds) return
 
@@ -610,15 +577,44 @@
         }
     }
 
-    private fun getDefaultDesktopTaskBounds(density: Float, stableBounds: Rect, outBounds: Rect) {
-        val width = (DESKTOP_MODE_DEFAULT_WIDTH_DP * density + 0.5f).toInt()
-        val height = (DESKTOP_MODE_DEFAULT_HEIGHT_DP * density + 0.5f).toInt()
-        outBounds.set(0, 0, width, height)
-        // Center the task in stable bounds
+    private fun getDefaultDesktopTaskBounds(displayLayout: DisplayLayout, outBounds: Rect) {
+        // TODO(b/319819547): Account for app constraints so apps do not become letterboxed
+        val screenBounds = Rect(0, 0, displayLayout.width(), displayLayout.height())
+        // Update width and height with default desktop mode values
+        val desiredWidth = screenBounds.width().times(DESKTOP_MODE_INITIAL_BOUNDS_SCALE).toInt()
+        val desiredHeight = screenBounds.height().times(DESKTOP_MODE_INITIAL_BOUNDS_SCALE).toInt()
+        outBounds.set(0, 0, desiredWidth, desiredHeight)
+        // Center the task in screen bounds
         outBounds.offset(
-            stableBounds.centerX() - outBounds.centerX(),
-            stableBounds.centerY() - outBounds.centerY()
-        )
+            screenBounds.centerX() - outBounds.centerX(),
+            screenBounds.centerY() - outBounds.centerY())
+    }
+
+    private fun getSnapBounds(taskInfo: RunningTaskInfo, position: SnapPosition): Rect {
+        val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return Rect()
+
+        val stableBounds = Rect()
+        displayLayout.getStableBounds(stableBounds)
+
+        val destinationWidth = stableBounds.width() / 2
+        return when (position) {
+            SnapPosition.LEFT -> {
+                Rect(
+                    stableBounds.left,
+                    stableBounds.top,
+                    stableBounds.left + destinationWidth,
+                    stableBounds.bottom
+                )
+            }
+            SnapPosition.RIGHT -> {
+                Rect(
+                    stableBounds.right - destinationWidth,
+                    stableBounds.top,
+                    stableBounds.right,
+                    stableBounds.bottom
+                )
+            }
+        }
     }
 
     /**
@@ -654,7 +650,7 @@
             ?.let { homeTask -> wct.reorder(homeTask.getToken(), true /* onTop */) }
     }
 
-    private fun releaseVisualIndicator() {
+    fun releaseVisualIndicator() {
         val t = SurfaceControl.Transaction()
         visualIndicator?.releaseVisualIndicator(t)
         visualIndicator = null
@@ -935,16 +931,13 @@
         taskSurface: SurfaceControl,
         inputX: Float,
         taskTop: Float
-    ) {
+    ): DesktopModeVisualIndicator.IndicatorType {
         // If the visual indicator does not exist, create it.
-        if (visualIndicator == null) {
-            visualIndicator = DesktopModeVisualIndicator(
-                syncQueue, taskInfo, displayController, context, taskSurface,
-                rootTaskDisplayAreaOrganizer)
-        }
-        // Then, update the indicator type.
-        val indicator = visualIndicator ?: return
-        indicator.updateIndicatorType(PointF(inputX, taskTop), taskInfo.windowingMode)
+        val indicator = visualIndicator ?: DesktopModeVisualIndicator(
+            syncQueue, taskInfo, displayController, context, taskSurface,
+            rootTaskDisplayAreaOrganizer)
+        if (visualIndicator == null) visualIndicator = indicator
+        return indicator.updateIndicatorType(PointF(inputX, taskTop), taskInfo.windowingMode)
     }
 
     /**
@@ -964,20 +957,28 @@
         if (taskInfo.configuration.windowConfiguration.windowingMode != WINDOWING_MODE_FREEFORM) {
             return
         }
-        if (taskBounds.top <= transitionAreaHeight) {
-            moveToFullscreenWithAnimation(taskInfo, position)
-            return
-        }
-        if (inputCoordinate.x <= transitionAreaWidth) {
-            releaseVisualIndicator()
-            snapToHalfScreen(taskInfo, SnapPosition.LEFT)
-            return
-        }
-        if (inputCoordinate.x >= (displayController.getDisplayLayout(taskInfo.displayId)?.width()
-            ?.minus(transitionAreaWidth) ?: return)) {
-            releaseVisualIndicator()
-            snapToHalfScreen(taskInfo, SnapPosition.RIGHT)
-            return
+
+        val indicator = visualIndicator ?: return
+        val indicatorType = indicator.updateIndicatorType(
+            PointF(inputCoordinate.x, taskBounds.top.toFloat()),
+            taskInfo.windowingMode
+        )
+        when (indicatorType) {
+            DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR -> {
+                moveToFullscreenWithAnimation(taskInfo, position)
+            }
+            DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR -> {
+                releaseVisualIndicator()
+                snapToHalfScreen(taskInfo, SnapPosition.LEFT)
+            }
+            DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR -> {
+                releaseVisualIndicator()
+                snapToHalfScreen(taskInfo, SnapPosition.RIGHT)
+            }
+            DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR,
+            DesktopModeVisualIndicator.IndicatorType.NO_INDICATOR -> {
+                releaseVisualIndicator()
+            }
         }
         // A freeform drag-move ended, remove the indicator immediately.
         releaseVisualIndicator()
@@ -990,14 +991,28 @@
      * @param y height of drag, to be checked against status bar height.
      */
     fun onDragPositioningEndThroughStatusBar(
+            inputCoordinates: PointF,
             taskInfo: RunningTaskInfo,
             freeformBounds: Rect
     ) {
-        finalizeDragToDesktop(taskInfo, freeformBounds)
-    }
-
-    private fun getStatusBarHeight(taskInfo: RunningTaskInfo): Int {
-        return displayController.getDisplayLayout(taskInfo.displayId)?.stableInsets()?.top ?: 0
+        val indicator = visualIndicator ?: return
+        val indicatorType = indicator
+            .updateIndicatorType(inputCoordinates, taskInfo.windowingMode)
+        when (indicatorType) {
+            DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR -> {
+                finalizeDragToDesktop(taskInfo, freeformBounds)
+            }
+            DesktopModeVisualIndicator.IndicatorType.NO_INDICATOR,
+                    DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR -> {
+                cancelDragToDesktop(taskInfo)
+            }
+            DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR -> {
+                finalizeDragToDesktop(taskInfo, getSnapBounds(taskInfo, SnapPosition.LEFT))
+            }
+            DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR -> {
+                finalizeDragToDesktop(taskInfo, getSnapBounds(taskInfo, SnapPosition.RIGHT))
+            }
+        }
     }
 
     /**
@@ -1113,6 +1128,12 @@
                 this@DesktopTasksController.enterDesktop(displayId)
             }
         }
+
+        override fun moveFocusedTaskToFullscreen(displayId: Int) {
+            mainExecutor.execute {
+                this@DesktopTasksController.enterFullscreen(displayId)
+            }
+        }
     }
 
     /** The interface for calls from outside the host process. */
@@ -1233,13 +1254,9 @@
             SystemProperties.getInt("persist.wm.debug.desktop_mode_density", 284)
         private val DESKTOP_DENSITY_ALLOWED_RANGE = (100..1000)
 
-        // Override default freeform task width when desktop mode is enabled. In dips.
-        private val DESKTOP_MODE_DEFAULT_WIDTH_DP =
-            SystemProperties.getInt("persist.wm.debug.desktop_mode.default_width", 840)
-
-        // Override default freeform task height when desktop mode is enabled. In dips.
-        private val DESKTOP_MODE_DEFAULT_HEIGHT_DP =
-            SystemProperties.getInt("persist.wm.debug.desktop_mode.default_height", 630)
+        @JvmField
+        val DESKTOP_MODE_INITIAL_BOUNDS_SCALE = SystemProperties
+                .getInt("persist.wm.debug.freeform_initial_bounds_scale", 75) / 100f
 
         /**
          * Check if desktop density override is enabled
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
index 07cf202..79bb540 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
@@ -54,8 +54,6 @@
     private final Transitions mTransitions;
     private final Supplier<SurfaceControl.Transaction> mTransactionSupplier;
 
-    // The size of the screen after drag relative to the fullscreen size
-    public static final float FINAL_FREEFORM_SCALE = 0.6f;
     public static final int FREEFORM_ANIMATION_DURATION = 336;
 
     private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index 1afbdf9..7da1b23 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -59,7 +59,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
-import com.android.internal.logging.InstanceId;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.launcher3.icons.IconProvider;
@@ -316,12 +315,11 @@
                     return false;
                 }
                 // TODO(b/290391688): Also update the session data with task stack changes
-                InstanceId loggerSessionId = mLogger.logStart(event);
-                pd.activeDragCount++;
-                pd.dragSession = new DragSession(mContext, ActivityTaskManager.getInstance(),
+                pd.dragSession = new DragSession(ActivityTaskManager.getInstance(),
                         mDisplayController.getDisplayLayout(displayId), event.getClipData());
                 pd.dragSession.update();
-                pd.dragLayout.prepare(pd.dragSession, loggerSessionId);
+                pd.activeDragCount++;
+                pd.dragLayout.prepare(pd.dragSession, mLogger.logStart(pd.dragSession));
                 setDropTargetWindowVisibility(pd, View.VISIBLE);
                 notifyListeners(l -> {
                     l.onDragStarted();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropEventLogger.java
index 2a7dd5a..75b126c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropEventLogger.java
@@ -53,17 +53,21 @@
     /**
      * Logs the start of a drag.
      */
-    public InstanceId logStart(DragEvent event) {
-        final ClipDescription description = event.getClipDescription();
-        final ClipData data = event.getClipData();
-        final ClipData.Item item = data.getItemAt(0);
-        mInstanceId = item.getIntent().getParcelableExtra(
-                ClipDescription.EXTRA_LOGGING_INSTANCE_ID);
+    public InstanceId logStart(DragSession session) {
+        mInstanceId = session.appData != null
+                ? session.appData.getParcelableExtra(ClipDescription.EXTRA_LOGGING_INSTANCE_ID,
+                        InstanceId.class)
+                : null;
         if (mInstanceId == null) {
             mInstanceId = mIdSequence.newInstanceId();
         }
-        mActivityInfo = item.getActivityInfo();
-        log(getStartEnum(description), mActivityInfo);
+        mActivityInfo = session.activityInfo;
+        if (session.appData != null) {
+            log(getStartEnum(session.getClipDescription()), mActivityInfo);
+        } else {
+            // TODO(b/255649902): Update this once we have a new enum
+            log(DragAndDropUiEventEnum.GLOBAL_APP_DRAG_START_ACTIVITY, mActivityInfo);
+        }
         return mInstanceId;
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index a31a773..eb82da8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -29,6 +29,8 @@
 import static android.content.Intent.EXTRA_SHORTCUT_ID;
 import static android.content.Intent.EXTRA_TASK_ID;
 import static android.content.Intent.EXTRA_USER;
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
@@ -52,9 +54,11 @@
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.util.Log;
 import android.util.Slog;
 
 import androidx.annotation.IntDef;
@@ -63,8 +67,10 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.logging.InstanceId;
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 
 import java.lang.annotation.Retention;
@@ -104,7 +110,9 @@
     void start(DragSession session, InstanceId loggerSessionId) {
         mLoggerSessionId = loggerSessionId;
         mSession = session;
-        RectF disallowHitRegion = (RectF) mSession.dragData.getExtra(EXTRA_DISALLOW_HIT_REGION);
+        RectF disallowHitRegion = mSession.appData != null
+                ? (RectF) mSession.appData.getExtra(EXTRA_DISALLOW_HIT_REGION)
+                : null;
         if (disallowHitRegion == null) {
             mDisallowHitRegion.setEmpty();
         } else {
@@ -223,7 +231,7 @@
     }
 
     @VisibleForTesting
-    void handleDrop(Target target, ClipData data) {
+    void handleDrop(Target target) {
         if (target == null || !mTargets.contains(target)) {
             return;
         }
@@ -238,41 +246,77 @@
             mSplitScreen.onDroppedToSplit(position, mLoggerSessionId);
         }
 
-        final ClipDescription description = data.getDescription();
-        final Intent dragData = mSession.dragData;
-        startClipDescription(description, dragData, position);
+        if (mSession.appData != null) {
+            launchApp(mSession, position);
+        } else {
+            launchIntent(mSession, position);
+        }
     }
 
-    private void startClipDescription(ClipDescription description, Intent intent,
-            @SplitPosition int position) {
+    /**
+     * Launches an app provided by SysUI.
+     */
+    private void launchApp(DragSession session, @SplitPosition int position) {
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Launching app data at position=%d",
+                position);
+        final ClipDescription description = session.getClipDescription();
         final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK);
         final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
         final ActivityOptions baseActivityOpts = ActivityOptions.makeBasic();
         baseActivityOpts.setDisallowEnterPictureInPictureWhileLaunching(true);
         final Bundle opts = baseActivityOpts.toBundle();
-        if (intent.hasExtra(EXTRA_ACTIVITY_OPTIONS)) {
-            opts.putAll(intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS));
+        if (session.appData.hasExtra(EXTRA_ACTIVITY_OPTIONS)) {
+            opts.putAll(session.appData.getBundleExtra(EXTRA_ACTIVITY_OPTIONS));
         }
         // Put BAL flags to avoid activity start aborted.
         opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, true);
         opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION, true);
-        final UserHandle user = intent.getParcelableExtra(EXTRA_USER);
+        final UserHandle user = session.appData.getParcelableExtra(EXTRA_USER);
 
         if (isTask) {
-            final int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID);
+            final int taskId = session.appData.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID);
             mStarter.startTask(taskId, position, opts);
         } else if (isShortcut) {
-            final String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
-            final String id = intent.getStringExtra(EXTRA_SHORTCUT_ID);
+            final String packageName = session.appData.getStringExtra(EXTRA_PACKAGE_NAME);
+            final String id = session.appData.getStringExtra(EXTRA_SHORTCUT_ID);
             mStarter.startShortcut(packageName, id, position, opts, user);
         } else {
-            final PendingIntent launchIntent = intent.getParcelableExtra(EXTRA_PENDING_INTENT);
+            final PendingIntent launchIntent =
+                    session.appData.getParcelableExtra(EXTRA_PENDING_INTENT);
+            if (Build.IS_DEBUGGABLE) {
+                if (!user.equals(launchIntent.getCreatorUserHandle())) {
+                    Log.e(TAG, "Expected app intent's EXTRA_USER to match pending intent user");
+                }
+            }
             mStarter.startIntent(launchIntent, user.getIdentifier(), null /* fillIntent */,
                     position, opts);
         }
     }
 
     /**
+     * Launches an intent sender provided by an application.
+     */
+    private void launchIntent(DragSession session, @SplitPosition int position) {
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Launching intent at position=%d",
+                position);
+        final ActivityOptions baseActivityOpts = ActivityOptions.makeBasic();
+        baseActivityOpts.setDisallowEnterPictureInPictureWhileLaunching(true);
+        // TODO(b/255649902): Rework this so that SplitScreenController can always use the options
+        // instead of a fillInIntent since it's assuming that the PendingIntent is mutable
+        baseActivityOpts.setPendingIntentLaunchFlags(FLAG_ACTIVITY_NEW_TASK
+                | FLAG_ACTIVITY_MULTIPLE_TASK);
+
+        final Bundle opts = baseActivityOpts.toBundle();
+        // Put BAL flags to avoid activity start aborted.
+        opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, true);
+        opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION, true);
+
+        mStarter.startIntent(session.launchableIntent,
+                session.launchableIntent.getCreatorUserHandle().getIdentifier(),
+                null /* fillIntent */, position, opts);
+    }
+
+    /**
      * Interface for actually committing the task launches.
      */
     public interface Starter {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index 619f624..ecb53dc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -22,6 +22,8 @@
 import static android.content.pm.ActivityInfo.CONFIG_ASSETS_PATHS;
 import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
+import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
 
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
@@ -38,12 +40,15 @@
 import android.app.StatusBarManager;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.Insets;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.graphics.drawable.Drawable;
 import android.view.DragEvent;
 import android.view.SurfaceControl;
+import android.view.ViewTreeObserver;
 import android.view.WindowInsets;
 import android.view.WindowInsets.Type;
 import android.widget.LinearLayout;
@@ -65,7 +70,8 @@
 /**
  * Coordinates the visible drop targets for the current drag within a single display.
  */
-public class DragLayout extends LinearLayout {
+public class DragLayout extends LinearLayout
+        implements ViewTreeObserver.OnComputeInternalInsetsListener {
 
     // While dragging the status bar is hidden.
     private static final int HIDE_STATUS_BAR_FLAGS = StatusBarManager.DISABLE_NOTIFICATION_ICONS
@@ -90,7 +96,9 @@
 
     private int mDisplayMargin;
     private int mDividerSize;
+    private int mLaunchIntentEdgeMargin;
     private Insets mInsets = Insets.NONE;
+    private Region mTouchableRegion;
 
     private boolean mIsShowing;
     private boolean mHasDropped;
@@ -106,10 +114,11 @@
         mStatusBarManager = context.getSystemService(StatusBarManager.class);
         mLastConfiguration.setTo(context.getResources().getConfiguration());
 
-        mDisplayMargin = context.getResources().getDimensionPixelSize(
-                R.dimen.drop_layout_display_margin);
-        mDividerSize = context.getResources().getDimensionPixelSize(
-                R.dimen.split_divider_bar_width);
+        final Resources res = context.getResources();
+        mDisplayMargin = res.getDimensionPixelSize(R.dimen.drop_layout_display_margin);
+        mDividerSize = res.getDimensionPixelSize(R.dimen.split_divider_bar_width);
+        mLaunchIntentEdgeMargin =
+                res.getDimensionPixelSize(R.dimen.drag_launchable_intent_edge_margin);
 
         // Always use LTR because we assume dropZoneView1 is on the left and 2 is on the right when
         // showing the highlight.
@@ -131,6 +140,66 @@
     }
 
     @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mTouchableRegion = Region.obtain();
+        getViewTreeObserver().addOnComputeInternalInsetsListener(this);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
+        mTouchableRegion.recycle();
+    }
+
+    @Override
+    public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inOutInfo) {
+        if (mSession != null && mSession.launchableIntent != null) {
+            inOutInfo.touchableRegion.set(mTouchableRegion);
+            inOutInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        updateTouchableRegion();
+    }
+
+    /**
+     * Updates the touchable region, this should be called after any configuration changes have
+     * been applied.
+     */
+    private void updateTouchableRegion() {
+        mTouchableRegion.setEmpty();
+        if (mSession != null && mSession.launchableIntent != null) {
+            final int width = getMeasuredWidth();
+            final int height = getMeasuredHeight();
+            if (mIsLeftRightSplit) {
+                mTouchableRegion.union(
+                        new Rect(0, 0, mInsets.left + mLaunchIntentEdgeMargin, height));
+                mTouchableRegion.union(
+                        new Rect(width - mInsets.right - mLaunchIntentEdgeMargin, 0, width,
+                                height));
+            } else {
+                mTouchableRegion.union(
+                        new Rect(0, 0, width, mInsets.top + mLaunchIntentEdgeMargin));
+                mTouchableRegion.union(
+                        new Rect(0, height - mInsets.bottom - mLaunchIntentEdgeMargin, width,
+                                height));
+            }
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
+                    "Updating drag layout width=%d height=%d touchable region=%s",
+                    width, height, mTouchableRegion);
+
+            // Reapply insets to update the touchable region
+            requestApplyInsets();
+        }
+    }
+
+
+    @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
         mInsets = insets.getInsets(Type.tappableElement() | Type.displayCutout());
         recomputeDropTargets();
@@ -164,6 +233,7 @@
             mDropZoneView2.onThemeChange();
         }
         mLastConfiguration.setTo(newConfig);
+        requestLayout();
     }
 
     private void updateContainerMarginsForSingleTask() {
@@ -242,6 +312,7 @@
             mSplitScreenController.getStageBounds(topOrLeftBounds, bottomOrRightBounds);
             updateDropZoneSizes(topOrLeftBounds, bottomOrRightBounds);
         }
+        requestLayout();
     }
 
     private void updateDropZoneSizesForSingleTask() {
@@ -392,7 +463,7 @@
         mHasDropped = true;
 
         // Process the drop
-        mPolicy.handleDrop(mCurrentTarget, event.getClipData());
+        mPolicy.handleDrop(mCurrentTarget);
 
         // Start animating the drop UI out with the drag surface
         hide(event, dropCompleteCallback);
@@ -505,5 +576,7 @@
         pw.println(innerPrefix + "mIsShowing=" + mIsShowing);
         pw.println(innerPrefix + "mHasDropped=" + mHasDropped);
         pw.println(innerPrefix + "mCurrentTarget=" + mCurrentTarget);
+        pw.println(innerPrefix + "mInsets=" + mInsets);
+        pw.println(innerPrefix + "mTouchableRegion=" + mTouchableRegion);
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
index 353d702..8f1bc59 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
@@ -21,12 +21,15 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
+import android.app.PendingIntent;
 import android.app.WindowConfiguration;
 import android.content.ClipData;
-import android.content.Context;
+import android.content.ClipDescription;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 
+import androidx.annotation.Nullable;
+
 import com.android.wm.shell.common.DisplayLayout;
 
 import java.util.List;
@@ -39,7 +42,18 @@
     private final ClipData mInitialDragData;
 
     final DisplayLayout displayLayout;
-    Intent dragData;
+    // The activity info associated with the activity in the appData or the launchableIntent
+    @Nullable
+    ActivityInfo activityInfo;
+    // The intent bundle that includes data about an app-type drag that is started by
+    // Launcher/SysUI.  Only one of appDragData OR launchableIntent will be non-null for a session.
+    @Nullable
+    Intent appData;
+    // A launchable intent that is specified in the ClipData directly.
+    // Only one of appDragData OR launchableIntent will be non-null for a session.
+    @Nullable
+    PendingIntent launchableIntent;
+    // Stores the current running task at the time that the drag was initiated
     ActivityManager.RunningTaskInfo runningTaskInfo;
     @WindowConfiguration.WindowingMode
     int runningTaskWinMode = WINDOWING_MODE_UNDEFINED;
@@ -47,7 +61,7 @@
     int runningTaskActType = ACTIVITY_TYPE_STANDARD;
     boolean dragItemSupportsSplitscreen;
 
-    DragSession(Context context, ActivityTaskManager activityTaskManager,
+    DragSession(ActivityTaskManager activityTaskManager,
             DisplayLayout dispLayout, ClipData data) {
         mActivityTaskManager = activityTaskManager;
         mInitialDragData = data;
@@ -55,6 +69,14 @@
     }
 
     /**
+     * Returns the clip description associated with the drag.
+     * @return
+     */
+    ClipDescription getClipDescription() {
+        return mInitialDragData.getDescription();
+    }
+
+    /**
      * Updates the session data based on the current state of the system.
      */
     void update() {
@@ -67,9 +89,11 @@
             runningTaskActType = task.getActivityType();
         }
 
-        final ActivityInfo info = mInitialDragData.getItemAt(0).getActivityInfo();
-        dragItemSupportsSplitscreen = info == null
-                || ActivityInfo.isResizeableMode(info.resizeMode);
-        dragData = mInitialDragData.getItemAt(0).getIntent();
+        activityInfo = mInitialDragData.getItemAt(0).getActivityInfo();
+        // TODO: This should technically check & respect config_supportsNonResizableMultiWindow
+        dragItemSupportsSplitscreen = activityInfo == null
+                || ActivityInfo.isResizeableMode(activityInfo.resizeMode);
+        appData = mInitialDragData.getItemAt(0).getIntent();
+        launchableIntent = DragUtils.getLaunchIntent(mInitialDragData);
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java
index f7bcc94..24f8e18 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java
@@ -36,8 +36,21 @@
      * Returns whether we can handle this particular drag.
      */
     public static boolean canHandleDrag(DragEvent event) {
-        return event.getClipData().getItemCount() > 0
-                && (isAppDrag(event.getClipDescription()));
+        if (event.getClipData().getItemCount() <= 0) {
+            // No clip data, ignore this drag
+            return false;
+        }
+        if (isAppDrag(event.getClipDescription())) {
+            // Clip data contains an app drag initiated from SysUI, handle it
+            return true;
+        }
+        if (com.android.window.flags.Flags.delegateUnhandledDrags()
+                && getLaunchIntent(event) != null) {
+            // Clip data contains a launchable intent drag, handle it
+            return true;
+        }
+        // Otherwise ignore
+        return false;
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index c7daf56..87e372c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -63,6 +63,7 @@
 import android.graphics.Rect;
 import android.os.RemoteException;
 import android.os.SystemProperties;
+import android.util.Rational;
 import android.view.Choreographer;
 import android.view.Display;
 import android.view.Surface;
@@ -126,6 +127,8 @@
             SystemProperties.getInt(
                     "persist.wm.debug.extra_content_overlay_fade_out_delay_ms", 400);
 
+    private static final float PIP_ASPECT_RATIO_MISMATCH_THRESHOLD = 0.005f;
+
     private final Context mContext;
     private final SyncTransactionQueue mSyncTransactionQueue;
     private final PipBoundsState mPipBoundsState;
@@ -767,6 +770,37 @@
                     mPictureInPictureParams.getTitle());
             mPipParamsChangedForwarder.notifySubtitleChanged(
                     mPictureInPictureParams.getSubtitle());
+
+            if (mPictureInPictureParams.hasSourceBoundsHint()
+                    && mPictureInPictureParams.hasSetAspectRatio()) {
+                Rational sourceRectHintAspectRatio = new Rational(
+                        mPictureInPictureParams.getSourceRectHint().width(),
+                        mPictureInPictureParams.getSourceRectHint().height());
+                if (sourceRectHintAspectRatio.compareTo(
+                        mPictureInPictureParams.getAspectRatio()) != 0) {
+                    ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                            "Aspect ratio of source rect hint (%d/%d) does not match the provided "
+                                    + "aspect ratio value (%d/%d). Consider matching them for "
+                                    + "improved animation. Future releases might override the "
+                                    + "value to match.",
+                            mPictureInPictureParams.getSourceRectHint().width(),
+                            mPictureInPictureParams.getSourceRectHint().height(),
+                            mPictureInPictureParams.getAspectRatio().getNumerator(),
+                            mPictureInPictureParams.getAspectRatio().getDenominator());
+                }
+                if (Math.abs(sourceRectHintAspectRatio.floatValue()
+                        - mPictureInPictureParams.getAspectRatioFloat())
+                        > PIP_ASPECT_RATIO_MISMATCH_THRESHOLD) {
+                    ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                            "Aspect ratio of source rect hint (%f) does not match the provided "
+                                    + "aspect ratio value (%f) and is above threshold of %f. "
+                                    + "Consider matching them for improved animation. Future "
+                                    + "releases might override the value to match.",
+                            sourceRectHintAspectRatio.floatValue(),
+                            mPictureInPictureParams.getAspectRatioFloat(),
+                            PIP_ASPECT_RATIO_MISMATCH_THRESHOLD);
+                }
+            }
         }
 
         mPipUiEventLoggerLogger.setTaskInfo(mTaskInfo);
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 e018ecc..6a1a62ea 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
@@ -1037,6 +1037,7 @@
     private void computeEnterPipRotatedBounds(int rotationDelta, int startRotation, int endRotation,
             TaskInfo taskInfo, Rect outDestinationBounds, @Nullable Rect outSourceHintRect) {
         mPipDisplayLayoutState.rotateTo(endRotation);
+        mPipBoundsState.updateMinMaxSize(mPipBoundsState.getAspectRatio());
 
         final Rect displayBounds = mPipDisplayLayoutState.getDisplayBounds();
         outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 4684077..4d47ca9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -122,6 +122,8 @@
     private static final long PIP_KEEP_CLEAR_AREAS_DELAY =
             SystemProperties.getLong("persist.wm.debug.pip_keep_clear_areas_delay", 200);
 
+    private static final long ENABLE_TOUCH_DELAY_MS = 200L;
+
     private Context mContext;
     protected ShellExecutor mMainExecutor;
     private DisplayController mDisplayController;
@@ -152,6 +154,8 @@
     private final Runnable mMovePipInResponseToKeepClearAreasChangeCallback =
             this::onKeepClearAreasChangedCallback;
 
+    private final Runnable mEnableTouchCallback = () -> mTouchHandler.setTouchEnabled(true);
+
     private void onKeepClearAreasChangedCallback() {
         if (mIsKeyguardShowingOrAnimating) {
             // early bail out if the change was caused by keyguard showing up
@@ -976,8 +980,16 @@
         mPipBoundsState.addNamedUnrestrictedKeepClearArea(LAUNCHER_KEEP_CLEAR_AREA_TAG,
                 hotseatKeepClearArea);
         onDisplayRotationChangedNotInPip(mContext, launcherRotation);
+        // cache current min/max size
+        Point minSize = mPipBoundsState.getMinSize();
+        Point maxSize = mPipBoundsState.getMaxSize();
+        mPipBoundsState.updateMinMaxSize(pictureInPictureParams.getAspectRatioFloat());
         final Rect entryBounds = mPipTaskOrganizer.startSwipePipToHome(componentName, activityInfo,
                 pictureInPictureParams);
+        // restore min/max size, as this is referenced later in OnDisplayChangingListener and needs
+        // to reflect the pre-rotation state for it to work
+        mPipBoundsState.setMinSize(minSize.x, minSize.y);
+        mPipBoundsState.setMaxSize(maxSize.x, maxSize.y);
         // sync mPipBoundsState with the newly calculated bounds.
         mPipBoundsState.setNormalBounds(entryBounds);
         return entryBounds;
@@ -1029,6 +1041,7 @@
             saveReentryState(pipBounds);
         }
         // Disable touches while the animation is running
+        mMainExecutor.removeCallbacks(mEnableTouchCallback);
         mTouchHandler.setTouchEnabled(false);
         if (mPinnedStackAnimationRecentsCallback != null) {
             mPinnedStackAnimationRecentsCallback.onPipAnimationStarted();
@@ -1059,7 +1072,7 @@
         InteractionJankMonitor.getInstance().end(CUJ_PIP_TRANSITION);
 
         // Re-enable touches after the animation completes
-        mTouchHandler.setTouchEnabled(true);
+        mMainExecutor.executeDelayed(mEnableTouchCallback, ENABLE_TOUCH_DELAY_MS);
         mTouchHandler.onPinnedStackAnimationEnded(direction);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index e7dd31c..c1adfff 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -467,17 +467,11 @@
     }
 
     private void updatePinchResizeSizeConstraints(float aspectRatio) {
-        final int minWidth, minHeight, maxWidth, maxHeight;
-
-        minWidth = mSizeSpecSource.getMinSize(aspectRatio).getWidth();
-        minHeight = mSizeSpecSource.getMinSize(aspectRatio).getHeight();
-        maxWidth = mSizeSpecSource.getMaxSize(aspectRatio).getWidth();
-        maxHeight = mSizeSpecSource.getMaxSize(aspectRatio).getHeight();
-
-        mPipResizeGestureHandler.updateMinSize(minWidth, minHeight);
-        mPipResizeGestureHandler.updateMaxSize(maxWidth, maxHeight);
-        mPipBoundsState.setMaxSize(maxWidth, maxHeight);
-        mPipBoundsState.setMinSize(minWidth, minHeight);
+        mPipBoundsState.updateMinMaxSize(aspectRatio);
+        mPipResizeGestureHandler.updateMinSize(mPipBoundsState.getMinSize().x,
+                mPipBoundsState.getMinSize().y);
+        mPipResizeGestureHandler.updateMaxSize(mPipBoundsState.getMaxSize().x,
+                mPipBoundsState.getMaxSize().y);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java
deleted file mode 100644
index 93ffb3d..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java
+++ /dev/null
@@ -1,120 +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.wm.shell.protolog;
-
-import android.annotation.Nullable;
-
-import com.android.internal.protolog.BaseProtoLogImpl;
-import com.android.internal.protolog.ProtoLogViewerConfigReader;
-import com.android.internal.protolog.common.IProtoLogGroup;
-
-import java.io.File;
-import java.io.PrintWriter;
-
-
-/**
- * A service for the ProtoLog logging system.
- */
-public class ShellProtoLogImpl extends BaseProtoLogImpl {
-    private static final String TAG = "ProtoLogImpl";
-    private static final int BUFFER_CAPACITY = 1024 * 1024;
-    // TODO: find a proper location to save the protolog message file
-    private static final String LOG_FILENAME = "/data/misc/wmtrace/shell_log.winscope";
-    private static final String VIEWER_CONFIG_FILENAME = "/system_ext/etc/wmshell.protolog.json.gz";
-
-    private static ShellProtoLogImpl sServiceInstance = null;
-
-    static {
-        addLogGroupEnum(ShellProtoLogGroup.values());
-    }
-
-    /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void d(IProtoLogGroup group, int messageHash, int paramsMask,
-            @Nullable String messageString,
-            Object... args) {
-        getSingleInstance()
-                .log(LogLevel.DEBUG, group, messageHash, paramsMask, messageString, args);
-    }
-
-    /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void v(IProtoLogGroup group, int messageHash, int paramsMask,
-            @Nullable String messageString,
-            Object... args) {
-        getSingleInstance().log(LogLevel.VERBOSE, group, messageHash, paramsMask, messageString,
-                args);
-    }
-
-    /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void i(IProtoLogGroup group, int messageHash, int paramsMask,
-            @Nullable String messageString,
-            Object... args) {
-        getSingleInstance().log(LogLevel.INFO, group, messageHash, paramsMask, messageString, args);
-    }
-
-    /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void w(IProtoLogGroup group, int messageHash, int paramsMask,
-            @Nullable String messageString,
-            Object... args) {
-        getSingleInstance().log(LogLevel.WARN, group, messageHash, paramsMask, messageString, args);
-    }
-
-    /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void e(IProtoLogGroup group, int messageHash, int paramsMask,
-            @Nullable String messageString,
-            Object... args) {
-        getSingleInstance()
-                .log(LogLevel.ERROR, group, messageHash, paramsMask, messageString, args);
-    }
-
-    /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void wtf(IProtoLogGroup group, int messageHash, int paramsMask,
-            @Nullable String messageString,
-            Object... args) {
-        getSingleInstance().log(LogLevel.WTF, group, messageHash, paramsMask, messageString, args);
-    }
-
-    /** Returns true iff logging is enabled for the given {@code IProtoLogGroup}. */
-    public static boolean isEnabled(IProtoLogGroup group) {
-        return group.isLogToLogcat()
-                || (group.isLogToProto() && getSingleInstance().isProtoEnabled());
-    }
-
-    /**
-     * Returns the single instance of the ProtoLogImpl singleton class.
-     */
-    public static synchronized ShellProtoLogImpl getSingleInstance() {
-        if (sServiceInstance == null) {
-            sServiceInstance = new ShellProtoLogImpl();
-        }
-        return sServiceInstance;
-    }
-
-    public int startTextLogging(String[] groups, PrintWriter pw) {
-        mViewerConfig.loadViewerConfig(pw, VIEWER_CONFIG_FILENAME);
-        return setLogging(true /* setTextLogging */, true, pw, groups);
-    }
-
-    public int stopTextLogging(String[] groups, PrintWriter pw) {
-        return setLogging(true /* setTextLogging */, false, pw, groups);
-    }
-
-    private ShellProtoLogImpl() {
-        super(new File(LOG_FILENAME), VIEWER_CONFIG_FILENAME, BUFFER_CAPACITY,
-                new ProtoLogViewerConfigReader());
-    }
-}
-
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 e421356..1c54754 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
@@ -163,14 +163,14 @@
     /**
      * Adds a split pair. This call does not validate the taskIds, only that they are not the same.
      */
-    public void addSplitPair(int taskId1, int taskId2, SplitBounds splitBounds) {
+    public boolean addSplitPair(int taskId1, int taskId2, SplitBounds splitBounds) {
         if (taskId1 == taskId2) {
-            return;
+            return false;
         }
         if (mSplitTasks.get(taskId1, INVALID_TASK_ID) == taskId2
                 && mTaskSplitBoundsMap.get(taskId1).equals(splitBounds)) {
             // If the two tasks are already paired and the bounds are the same, then skip updating
-            return;
+            return false;
         }
         // Remove any previous pairs
         removeSplitPair(taskId1);
@@ -185,6 +185,7 @@
         notifyRecentTasksChanged();
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENT_TASKS, "Add split pair: %d, %d, %s",
                 taskId1, taskId2, splitBounds);
+        return true;
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
index e52235f..64e26db 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
@@ -16,11 +16,14 @@
 
 package com.android.wm.shell.splitscreen;
 
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
+
 import android.content.Context;
 import android.view.SurfaceSession;
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.SyncTransactionQueue;
@@ -50,6 +53,8 @@
 
     void activate(WindowContainerTransaction wct, boolean includingTopTask) {
         if (mIsActive) return;
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "activate: main stage includingTopTask=%b",
+                includingTopTask);
 
         if (includingTopTask) {
             reparentTopTask(wct);
@@ -64,6 +69,8 @@
 
     void deactivate(WindowContainerTransaction wct, boolean toTop) {
         if (!mIsActive) return;
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "deactivate: main stage toTop=%b rootTaskInfo=%s",
+                toTop, mRootTaskInfo);
         mIsActive = false;
 
         if (mRootTaskInfo == null) return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OWNERS
index 7237d2b..37ccd15 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OWNERS
@@ -1,2 +1,4 @@
 # WM shell sub-modules splitscreen owner
 chenghsiuchang@google.com
+jeremysim@google.com
+peanutbutter@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
index 9903113..f5fbae5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
@@ -16,12 +16,15 @@
 
 package com.android.wm.shell.splitscreen;
 
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
+
 import android.app.ActivityManager;
 import android.content.Context;
 import android.view.SurfaceSession;
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.SyncTransactionQueue;
@@ -47,6 +50,8 @@
     }
 
     boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "remove all side stage tasks: childCount=%d toTop=%b",
+                mChildrenTaskInfo.size(), toTop);
         if (mChildrenTaskInfo.size() == 0) return false;
         wct.reparentTasks(
                 mRootTaskInfo.token,
@@ -59,6 +64,8 @@
 
     boolean removeTask(int taskId, WindowContainerToken newParent, WindowContainerTransaction wct) {
         final ActivityManager.RunningTaskInfo task = mChildrenTaskInfo.get(taskId);
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "remove side stage task: task=%d exists=%b", taskId,
+                task != null);
         if (task == null) return false;
         wct.reparent(task.token, newParent, false /* onTop */);
         return true;
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 53dd981..952e2d4 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
@@ -476,7 +476,9 @@
     }
 
     public void goToFullscreenFromSplit() {
-        mStageCoordinator.goToFullscreenFromSplit();
+        if (mStageCoordinator.isSplitActive()) {
+            mStageCoordinator.goToFullscreenFromSplit();
+        }
     }
 
     /** Move the specified task to fullscreen, regardless of focus state. */
@@ -806,6 +808,9 @@
     @Override
     public void startIntent(PendingIntent intent, int userId1, @Nullable Intent fillInIntent,
             @SplitPosition int position, @Nullable Bundle options) {
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+                "startIntent(): intent=%s user=%d fillInIntent=%s position=%d", intent, userId1,
+                fillInIntent, position);
         // Flag this as a no-user-action launch to prevent sending user leaving event to the current
         // top activity since it's going to be put into another side of the split. This prevents the
         // current top activity from going into pip mode due to user leaving event.
@@ -824,6 +829,8 @@
                 .map(recentTasks -> recentTasks.findTaskInBackground(component, userId1))
                 .orElse(null);
         if (taskInfo != null) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+                    "Found suitable background task=%s", taskInfo);
             if (ENABLE_SHELL_TRANSITIONS) {
                 mStageCoordinator.startTask(taskInfo.taskId, position, options);
             } else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index b60e361..1a53a1d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -25,6 +25,8 @@
 import static com.android.wm.shell.animation.Interpolators.ALPHA_OUT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.FADE_DURATION;
 import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TRANSITIONS;
 import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString;
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
 import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
@@ -101,6 +103,7 @@
             @NonNull Transitions.TransitionFinishCallback finishCallback,
             @NonNull WindowContainerToken mainRoot, @NonNull WindowContainerToken sideRoot,
             @NonNull WindowContainerToken topRoot) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "playAnimation: transition=%d", info.getDebugId());
         initTransition(transition, finishTransaction, finishCallback);
 
         final TransitSession pendingTransition = getPendingTransition(transition);
@@ -123,10 +126,12 @@
         playInternalAnimation(transition, info, startTransaction, mainRoot, sideRoot, topRoot);
     }
 
-    /** Internal funcation of playAnimation. */
+    /** Internal function of playAnimation. */
     private void playInternalAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
             @NonNull SurfaceControl.Transaction t, @NonNull WindowContainerToken mainRoot,
             @NonNull WindowContainerToken sideRoot, @NonNull WindowContainerToken topRoot) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "playInternalAnimation: transition=%d",
+                info.getDebugId());
         // Play some place-holder fade animations
         final boolean isEnter = isPendingEnter(transition);
         for (int i = info.getChanges().size() - 1; i >= 0; --i) {
@@ -220,6 +225,8 @@
             @NonNull Transitions.TransitionFinishCallback finishCallback,
             @NonNull WindowContainerToken toTopRoot, @NonNull SplitDecorManager toTopDecor,
             @NonNull WindowContainerToken topRoot) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "playDragDismissAnimation: transition=%d",
+                info.getDebugId());
         initTransition(transition, finishTransaction, finishCallback);
 
         for (int i = info.getChanges().size() - 1; i >= 0; --i) {
@@ -259,6 +266,7 @@
             @NonNull Transitions.TransitionFinishCallback finishCallback,
             @NonNull WindowContainerToken mainRoot, @NonNull WindowContainerToken sideRoot,
             @NonNull SplitDecorManager mainDecor, @NonNull SplitDecorManager sideDecor) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "playResizeAnimation: transition=%d", info.getDebugId());
         initTransition(transition, finishTransaction, finishCallback);
 
         for (int i = info.getChanges().size() - 1; i >= 0; --i) {
@@ -312,13 +320,15 @@
     @Nullable
     private TransitSession getPendingTransition(IBinder transition) {
         if (isPendingEnter(transition)) {
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "\tresolved enter transition");
             return mPendingEnter;
         } else if (isPendingDismiss(transition)) {
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "\tresolved dismiss transition");
             return mPendingDismiss;
         } else if (isPendingResize(transition)) {
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "\tresolved resize transition");
             return mPendingResize;
         }
-
         return null;
     }
 
@@ -339,7 +349,7 @@
             Transitions.TransitionHandler handler,
             int extraTransitType, boolean resizeAnim) {
         if (mPendingEnter != null) {
-            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  splitTransition "
+            ProtoLog.v(WM_SHELL_TRANSITIONS, "  splitTransition "
                     + " skip to start enter split transition since it already exist. ");
             return null;
         }
@@ -355,8 +365,10 @@
         mPendingEnter = new EnterSession(
                 transition, remoteTransition, extraTransitType, resizeAnim);
 
-        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  splitTransition "
+        ProtoLog.v(WM_SHELL_TRANSITIONS, "  splitTransition "
                 + " deduced Enter split screen");
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "setEnterTransition: transitType=%d resize=%b",
+                extraTransitType, resizeAnim);
     }
 
     /** Starts a transition to dismiss split. */
@@ -364,7 +376,7 @@
             Transitions.TransitionHandler handler, @SplitScreen.StageType int dismissTop,
             @SplitScreenController.ExitReason int reason) {
         if (mPendingDismiss != null) {
-            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  splitTransition "
+            ProtoLog.v(WM_SHELL_TRANSITIONS, "  splitTransition "
                     + " skip to start dismiss split transition since it already exist. reason to "
                     + " dismiss = %s", exitReasonToString(reason));
             return null;
@@ -381,32 +393,33 @@
             @SplitScreenController.ExitReason int reason) {
         mPendingDismiss = new DismissSession(transition, reason, dismissTop);
 
-        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  splitTransition "
+        ProtoLog.v(WM_SHELL_TRANSITIONS, "  splitTransition "
                         + " deduced Dismiss due to %s. toTop=%s",
                 exitReasonToString(reason), stageTypeToString(dismissTop));
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "setDismissTransition: reason=%s dismissTop=%s",
+                exitReasonToString(reason), stageTypeToString(dismissTop));
     }
 
     IBinder startResizeTransition(WindowContainerTransaction wct,
             Transitions.TransitionHandler handler,
             @Nullable TransitionConsumedCallback consumedCallback,
-            @Nullable TransitionFinishedCallback finishCallback) {
+            @Nullable TransitionFinishedCallback finishCallback,
+            @NonNull SplitDecorManager mainDecor, @NonNull SplitDecorManager sideDecor) {
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+                "  splitTransition deduced Resize split screen.");
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "setResizeTransition: hasPendingResize=%b",
+                mPendingResize != null);
         if (mPendingResize != null) {
+            mainDecor.cancelRunningAnimations();
+            sideDecor.cancelRunningAnimations();
             mPendingResize.cancel(null);
             mAnimations.clear();
             onFinish(null /* wct */);
         }
 
         IBinder transition = mTransitions.startTransition(TRANSIT_CHANGE, wct, handler);
-        setResizeTransition(transition, consumedCallback, finishCallback);
-        return transition;
-    }
-
-    void setResizeTransition(@NonNull IBinder transition,
-            @Nullable TransitionConsumedCallback consumedCallback,
-            @Nullable TransitionFinishedCallback finishCallback) {
         mPendingResize = new TransitSession(transition, consumedCallback, finishCallback);
-        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  splitTransition "
-                + " deduced Resize split screen");
+        return transition;
     }
 
     void mergeAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t,
@@ -444,12 +457,15 @@
 
             mPendingEnter.onConsumed(aborted);
             mPendingEnter = null;
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTransitionConsumed for enter transition");
         } else if (isPendingDismiss(transition)) {
             mPendingDismiss.onConsumed(aborted);
             mPendingDismiss = null;
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTransitionConsumed for dismiss transition");
         } else if (isPendingResize(transition)) {
             mPendingResize.onConsumed(aborted);
             mPendingResize = null;
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTransitionConsumed for resize transition");
         }
 
         // TODO: handle transition consumed for active remote handler
@@ -462,12 +478,15 @@
         if (isPendingEnter(mAnimatingTransition)) {
             mPendingEnter.onFinished(wct, mFinishTransaction);
             mPendingEnter = null;
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onFinish for enter transition");
         } else if (isPendingDismiss(mAnimatingTransition)) {
             mPendingDismiss.onFinished(wct, mFinishTransaction);
             mPendingDismiss = null;
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onFinish for dismiss transition");
         } else if (isPendingResize(mAnimatingTransition)) {
             mPendingResize.onFinished(wct, mFinishTransaction);
             mPendingResize = null;
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onFinish for resize transition");
         }
 
         mActiveRemoteHandler = null;
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 fa14b4c..7650444 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
@@ -44,6 +44,7 @@
 import static com.android.wm.shell.common.split.SplitScreenConstants.splitPositionToString;
 import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
 import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
 import static com.android.wm.shell.shared.TransitionUtil.isClosingType;
 import static com.android.wm.shell.shared.TransitionUtil.isOpeningType;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
@@ -54,6 +55,7 @@
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW;
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_FINISHED;
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DESKTOP_MODE;
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DEVICE_FOLDED;
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_FULLSCREEN_SHORTCUT;
@@ -138,6 +140,7 @@
 import com.android.wm.shell.shared.TransitionUtil;
 import com.android.wm.shell.splitscreen.SplitScreen.StageType;
 import com.android.wm.shell.splitscreen.SplitScreenController.ExitReason;
+import com.android.wm.shell.splitscreen.SplitScreenController.SplitEnterReason;
 import com.android.wm.shell.transition.DefaultMixedHandler;
 import com.android.wm.shell.transition.LegacyTransitions;
 import com.android.wm.shell.transition.Transitions;
@@ -313,6 +316,7 @@
 
         taskOrganizer.createRootTask(displayId, WINDOWING_MODE_FULLSCREEN, this /* listener */);
 
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Creating main/side root task");
         mMainStage = new MainStage(
                 mContext,
                 mTaskOrganizer,
@@ -454,6 +458,8 @@
 
     boolean moveToStage(ActivityManager.RunningTaskInfo task, @SplitPosition int stagePosition,
             WindowContainerTransaction wct) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "moveToStage: task=%d position=%d", task.taskId,
+                stagePosition);
         prepareEnterSplitScreen(wct, task, stagePosition, false /* resizeAnim */);
         if (ENABLE_SHELL_TRANSITIONS) {
             mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct,
@@ -474,6 +480,7 @@
     }
 
     boolean removeFromSideStage(int taskId) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "removeFromSideStage: task=%d", taskId);
         final WindowContainerTransaction wct = new WindowContainerTransaction();
 
         /**
@@ -498,11 +505,15 @@
             enteredSplitSelect |= listener.onRequestEnterSplitSelect(taskInfo, splitPosition,
                     taskBounds);
         }
-        if (enteredSplitSelect) mTaskOrganizer.applyTransaction(wct);
+        if (enteredSplitSelect) {
+            mTaskOrganizer.applyTransaction(wct);
+        }
     }
 
     void startShortcut(String packageName, String shortcutId, @SplitPosition int position,
             Bundle options, UserHandle user) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "startShortcut: pkg=%s id=%s position=%d user=%d",
+                packageName, shortcutId, position, user.getIdentifier());
         final boolean isEnteringSplit = !isSplitActive();
 
         IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
@@ -564,6 +575,7 @@
 
     /** Use this method to launch an existing Task via a taskId */
     void startTask(int taskId, @SplitPosition int position, @Nullable Bundle options) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "startTask: task=%d position=%d", taskId, position);
         mSplitRequest = new SplitRequest(taskId, position);
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         options = resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, null /* wct */);
@@ -595,6 +607,8 @@
     /** Launches an activity into split. */
     void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
             @Nullable Bundle options) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "startIntent: intent=%s position=%d", intent.getIntent(),
+                position);
         mSplitRequest = new SplitRequest(intent.getIntent(), position);
         if (!ENABLE_SHELL_TRANSITIONS) {
             startIntentLegacy(intent, fillInIntent, position, options);
@@ -690,6 +704,9 @@
     void startTasks(int taskId1, @Nullable Bundle options1, int taskId2, @Nullable Bundle options2,
             @SplitPosition int splitPosition, @PersistentSnapPosition int snapPosition,
             @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+                "startTasks: task1=%d task2=%d position=%d snapPosition=%d",
+                taskId1, taskId2, splitPosition, snapPosition);
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         if (taskId2 == INVALID_TASK_ID) {
             if (mMainStage.containsTask(taskId1) || mSideStage.containsTask(taskId1)) {
@@ -718,6 +735,9 @@
             @Nullable Bundle options1, int taskId, @Nullable Bundle options2,
             @SplitPosition int splitPosition, @PersistentSnapPosition int snapPosition,
             @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+                "startIntentAndTask: intent=%s task1=%d position=%d snapPosition=%d",
+                pendingIntent.getIntent(), taskId, splitPosition, snapPosition);
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         if (taskId == INVALID_TASK_ID) {
             options1 = options1 != null ? options1 : new Bundle();
@@ -740,6 +760,9 @@
             int taskId, @Nullable Bundle options2, @SplitPosition int splitPosition,
             @PersistentSnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition,
             InstanceId instanceId) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+                "startShortcutAndTask: shortcut=%s task1=%d position=%d snapPosition=%d",
+                shortcutInfo, taskId, splitPosition, snapPosition);
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         if (taskId == INVALID_TASK_ID) {
             options1 = options1 != null ? options1 : new Bundle();
@@ -801,6 +824,10 @@
             @Nullable ShortcutInfo shortcutInfo2, @Nullable Bundle options2,
             @SplitPosition int splitPosition, @PersistentSnapPosition int snapPosition,
             @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+                "startIntents: intent1=%s intent2=%s position=%d snapPosition=%d",
+                pendingIntent1.getIntent(), pendingIntent2.getIntent(), splitPosition,
+                snapPosition);
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         if (pendingIntent2 == null) {
             options1 = options1 != null ? options1 : new Bundle();
@@ -1302,6 +1329,7 @@
     }
 
     void switchSplitPosition(String reason) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "switchSplitPosition");
         final SurfaceControl.Transaction t = mTransactionPool.acquire();
         mTempRect1.setEmpty();
         final StageTaskListener topLeftStage =
@@ -1343,7 +1371,7 @@
                     });
                 });
 
-        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Switch split position: %s", reason);
+        ProtoLog.v(WM_SHELL_SPLIT_SCREEN, "Switch split position: %s", reason);
         mLogger.logSwap(getMainStagePosition(), mMainStage.getTopChildTaskUid(),
                 getSideStagePosition(), mSideStage.getTopChildTaskUid(),
                 mSplitLayout.isLeftRightSplit());
@@ -1376,11 +1404,12 @@
         if (!mMainStage.isActive()) {
             return;
         }
-
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onKeyguardVisibilityChanged: showing=%b", showing);
         setDividerVisibility(!mKeyguardShowing, null);
     }
 
     void onFinishedWakingUp() {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onFinishedWakingUp");
         if (!mMainStage.isActive()) {
             return;
         }
@@ -1421,6 +1450,8 @@
     }
 
     void exitSplitScreen(int toTopTaskId, @ExitReason int exitReason) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "exitSplitScreen: topTaskId=%d reason=%s active=%b",
+                toTopTaskId, exitReasonToString(exitReason), mMainStage.isActive());
         if (!mMainStage.isActive()) return;
 
         StageTaskListener childrenToTop = null;
@@ -1439,6 +1470,8 @@
 
     private void exitSplitScreen(@Nullable StageTaskListener childrenToTop,
             @ExitReason int exitReason) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "exitSplitScreen: mainStageToTop=%b reason=%s active=%b",
+                childrenToTop == mMainStage, exitReasonToString(exitReason), mMainStage.isActive());
         if (!mMainStage.isActive()) return;
 
         final WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -1447,6 +1480,8 @@
 
     private void applyExitSplitScreen(@Nullable StageTaskListener childrenToTop,
             WindowContainerTransaction wct, @ExitReason int exitReason) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "applyExitSplitScreen: reason=%s",
+                exitReasonToString(exitReason));
         if (!mMainStage.isActive() || mIsExiting) return;
 
         onSplitScreenExit();
@@ -1502,7 +1537,6 @@
             }
         });
 
-        Slog.i(TAG, "applyExitSplitScreen, reason = " + exitReasonToString(exitReason));
         // Log the exit
         if (childrenToTop != null) {
             logExitToStage(exitReason, childrenToTop == mMainStage);
@@ -1527,6 +1561,7 @@
      * Exits the split screen by finishing one of the tasks.
      */
     protected void exitStage(@SplitPosition int stageToClose) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "exitStage: stageToClose=%d", stageToClose);
         mSplitLayout.flingDividerToDismiss(stageToClose == SPLIT_POSITION_BOTTOM_OR_RIGHT,
                 EXIT_REASON_APP_FINISHED);
     }
@@ -1540,12 +1575,13 @@
         try {
             activityTaskManagerService.setFocusedTask(getTaskId(stageToFocus));
         } catch (RemoteException | NullPointerException e) {
-            ProtoLog.e(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+            ProtoLog.e(WM_SHELL_SPLIT_SCREEN,
                     "Unable to update focus on the chosen stage: %s", e.getMessage());
         }
     }
 
     private void clearRequestIfPresented() {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "clearRequestIfPresented");
         if (mSideStageListener.mVisible && mSideStageListener.mHasChildren
                 && mMainStageListener.mVisible && mSideStageListener.mHasChildren) {
             mSplitRequest = null;
@@ -1572,6 +1608,8 @@
                 // The device is folded
             case EXIT_REASON_FULLSCREEN_SHORTCUT:
                 // User has used a keyboard shortcut to go back to fullscreen from split
+            case EXIT_REASON_DESKTOP_MODE:
+                // One of the children enters desktop mode
                 return true;
             default:
                 return false;
@@ -1581,6 +1619,8 @@
     void clearSplitPairedInRecents(@ExitReason int exitReason) {
         if (!shouldBreakPairedTaskInRecents(exitReason) || !mShouldUpdateRecents) return;
 
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "clearSplitPairedInRecents: reason=%s",
+                exitReasonToString(exitReason));
         mRecentTasks.ifPresent(recentTasks -> {
             // Notify recents if we are exiting in a way that breaks the pair, and disable further
             // updates to splits in the recents until we enter split again
@@ -1597,11 +1637,13 @@
     void prepareExitSplitScreen(@StageType int stageToTop,
             @NonNull WindowContainerTransaction wct) {
         if (!mMainStage.isActive()) return;
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareExitSplitScreen: stageToTop=%d", stageToTop);
         mSideStage.removeAllTasks(wct, stageToTop == STAGE_TYPE_SIDE);
         mMainStage.deactivate(wct, stageToTop == STAGE_TYPE_MAIN);
     }
 
     private void prepareEnterSplitScreen(WindowContainerTransaction wct) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareEnterSplitScreen");
         prepareEnterSplitScreen(wct, null /* taskInfo */, SPLIT_POSITION_UNDEFINED,
                 !mIsDropEntering);
     }
@@ -1613,6 +1655,8 @@
     void prepareEnterSplitScreen(WindowContainerTransaction wct,
             @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition,
             boolean resizeAnim) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareEnterSplitScreen: position=%d resize=%b",
+                startPosition, resizeAnim);
         onSplitScreenEnter();
         // Preemptively reset the reparenting behavior if we know that we are entering, as starting
         // split tasks with activity trampolines can inadvertently trigger the task to be
@@ -1629,6 +1673,8 @@
     private void prepareBringSplit(WindowContainerTransaction wct,
             @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition,
             boolean resizeAnim) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareBringSplit: task=%d isSplitVisible=%b",
+                taskInfo != null ? taskInfo.taskId : -1, isSplitScreenVisible());
         if (taskInfo != null) {
             wct.startTask(taskInfo.taskId,
                     resolveStartStage(STAGE_TYPE_UNDEFINED, startPosition, null, wct));
@@ -1649,6 +1695,8 @@
     private void prepareActiveSplit(WindowContainerTransaction wct,
             @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition,
             boolean resizeAnim) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareActiveSplit: task=%d isSplitVisible=%b",
+                taskInfo != null ? taskInfo.taskId : -1, isSplitScreenVisible());
         if (!ENABLE_SHELL_TRANSITIONS) {
             // Legacy transition we need to create divider here, shell transition case we will
             // create it on #finishEnterSplitScreen
@@ -1667,6 +1715,7 @@
     }
 
     private void prepareSplitLayout(WindowContainerTransaction wct, boolean resizeAnim) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareSplitLayout: resize=%b", resizeAnim);
         if (resizeAnim) {
             mSplitLayout.setDividerAtBorder(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT);
         } else {
@@ -1686,6 +1735,7 @@
     }
 
     void finishEnterSplitScreen(SurfaceControl.Transaction finishT) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "finishEnterSplitScreen");
         mSplitLayout.update(finishT, true /* resetImePosition */);
         mMainStage.getSplitDecorManager().inflate(mContext, mMainStage.mRootLeash,
                 getMainStageBounds());
@@ -1835,12 +1885,20 @@
                     leftTopTaskId, rightBottomTaskId, mSplitLayout.calculateCurrentSnapPosition());
             if (mainStageTopTaskId != INVALID_TASK_ID && sideStageTopTaskId != INVALID_TASK_ID) {
                 // Update the pair for the top tasks
-                recentTasks.addSplitPair(mainStageTopTaskId, sideStageTopTaskId, splitBounds);
+                boolean added = recentTasks.addSplitPair(mainStageTopTaskId, sideStageTopTaskId,
+                        splitBounds);
+                if (added) {
+                    ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+                            "updateRecentTasksSplitPair: adding split pair ltTask=%d rbTask=%d",
+                            leftTopTaskId, rightBottomTaskId);
+                }
             }
         });
     }
 
     private void sendSplitVisibilityChanged() {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "sendSplitVisibilityChanged: dividerVisible=%b",
+                mDividerVisible);
         for (int i = mListeners.size() - 1; i >= 0; --i) {
             final SplitScreen.SplitScreenListener l = mListeners.get(i);
             l.onSplitVisibilityChanged(mDividerVisible);
@@ -1855,6 +1913,7 @@
             throw new IllegalArgumentException(this + "\n Unknown task appeared: " + taskInfo);
         }
 
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskAppeared: task=%s", taskInfo);
         mRootTaskInfo = taskInfo;
         mRootTaskLeash = leash;
 
@@ -1880,6 +1939,8 @@
         if (mSplitLayout != null
                 && mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)
                 && mMainStage.isActive()) {
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskInfoChanged: task=%d updating",
+                    taskInfo.taskId);
             // Clear the divider remote animating flag as the divider will be re-rendered to apply
             // the new rotation config.  Don't reset the IME state since those updates are not in
             // sync with task info changes.
@@ -1892,6 +1953,7 @@
     @Override
     @CallSuper
     public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskVanished: task=%s", taskInfo);
         if (mRootTaskInfo == null) {
             throw new IllegalArgumentException(this + "\n Unknown task vanished: " + taskInfo);
         }
@@ -1911,6 +1973,8 @@
 
     @VisibleForTesting
     void onRootTaskAppeared() {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onRootTaskAppeared: rootTask=%s mainRoot=%b sideRoot=%b",
+                mRootTaskInfo, mMainStageListener.mHasRootTask, mSideStageListener.mHasRootTask);
         // Wait unit all root tasks appeared.
         if (mRootTaskInfo == null
                 || !mMainStageListener.mHasRootTask
@@ -1937,6 +2001,8 @@
      * #onStageHasChildrenChanged because this would be called every time child task appeared.
      * NOTICE: This only be called on legacy transition. */
     private void onChildTaskAppeared(StageListenerImpl stageListener, int taskId) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onChildTaskAppeared: isMainStage=%b task=%d",
+                stageListener == mMainStageListener, taskId);
         // Handle entering split screen while there is a split pair running in the background.
         if (stageListener == mSideStageListener && !isSplitScreenVisible() && isSplitActive()
                 && mSplitRequest == null) {
@@ -1960,6 +2026,7 @@
     }
 
     private void onRootTaskVanished() {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onRootTaskVanished");
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         mLaunchAdjacentController.clearLaunchAdjacentRoot();
         applyExitSplitScreen(null /* childrenToTop */, wct, EXIT_REASON_ROOT_TASK_VANISHED);
@@ -1990,6 +2057,8 @@
             return;
         }
 
+        // TODO Protolog
+
         // Check if it needs to dismiss split screen when both stage invisible.
         if (!mainStageVisible && mExitSplitScreenOnHide) {
             exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RETURN_HOME);
@@ -2020,14 +2089,14 @@
             return;
         }
 
-        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
-                "Request to %s divider bar from %s.",
-                (visible ? "show" : "hide"), Debug.getCaller());
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+                "setDividerVisibility: visible=%b keyguardShowing=%b dividerAnimating=%b caller=%s",
+                visible, mKeyguardShowing, mIsDividerRemoteAnimating, Debug.getCaller());
 
         // Defer showing divider bar after keyguard dismissed, so it won't interfere with keyguard
         // dismissing animation.
         if (visible && mKeyguardShowing) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
                     "   Defer showing divider bar due to keyguard showing.");
             return;
         }
@@ -2036,7 +2105,7 @@
         sendSplitVisibilityChanged();
 
         if (mIsDividerRemoteAnimating) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
                     "   Skip animating divider bar due to it's remote animating.");
             return;
         }
@@ -2050,12 +2119,12 @@
     private void applyDividerVisibility(@Nullable SurfaceControl.Transaction t) {
         final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
         if (dividerLeash == null) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
                     "   Skip animating divider bar due to divider leash not ready.");
             return;
         }
         if (mIsDividerRemoteAnimating) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
                     "   Skip animating divider bar due to it's remote animating.");
             return;
         }
@@ -2119,6 +2188,8 @@
     /** Callback when split roots have child or haven't under it.
      * NOTICE: This only be called on legacy transition. */
     private void onStageHasChildrenChanged(StageListenerImpl stageListener) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onStageHasChildrenChanged: isMainStage=%b",
+                stageListener == mMainStageListener);
         final boolean hasChildren = stageListener.mHasChildren;
         final boolean isSideStage = stageListener == mSideStageListener;
         if (!hasChildren && !mIsExiting && mMainStage.isActive()) {
@@ -2170,13 +2241,15 @@
     }
 
     @Override
-    public void onSnappedToDismiss(boolean bottomOrRight, int reason) {
+    public void onSnappedToDismiss(boolean bottomOrRight, @ExitReason int exitReason) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onSnappedToDismiss: bottomOrRight=%b reason=%s",
+                bottomOrRight, exitReasonToString(exitReason));
         final boolean mainStageToTop =
                 bottomOrRight ? mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
                         : mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT;
         final StageTaskListener toTopStage = mainStageToTop ? mMainStage : mSideStage;
         if (!ENABLE_SHELL_TRANSITIONS) {
-            exitSplitScreen(toTopStage, reason);
+            exitSplitScreen(toTopStage, exitReason);
             return;
         }
 
@@ -2219,6 +2292,7 @@
 
     @Override
     public void onLayoutSizeChanged(SplitLayout layout) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onLayoutSizeChanged");
         // Reset this flag every time onLayoutSizeChanged.
         mShowDecorImmediately = false;
 
@@ -2237,10 +2311,10 @@
         if (ENABLE_SHELL_TRANSITIONS) {
             mSplitLayout.setDividerInteractive(false, false, "onSplitResizeStart");
             mSplitTransitions.startResizeTransition(wct, this, (aborted) -> {
-                mSplitLayout.setDividerInteractive(true, false, "onSplitResizeConsumed");
-            }, (finishWct, t) -> {
-                mSplitLayout.setDividerInteractive(true, false, "onSplitResizeFinish");
-            });
+                        mSplitLayout.setDividerInteractive(true, false, "onSplitResizeConsumed");
+                    }, (finishWct, t) -> {
+                        mSplitLayout.setDividerInteractive(true, false, "onSplitResizeFinish");
+                    }, mMainStage.getSplitDecorManager(), mSideStage.getSplitDecorManager());
         } else {
             // Only need screenshot for legacy case because shell transition should screenshot
             // itself during transition.
@@ -2278,8 +2352,11 @@
                 mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
         final StageTaskListener bottomRightStage =
                 mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
-        return layout.applyTaskChanges(wct, topLeftStage.mRootTaskInfo,
+        boolean updated = layout.applyTaskChanges(wct, topLeftStage.mRootTaskInfo,
                 bottomRightStage.mRootTaskInfo);
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "updateWindowBounds: topLeftStage=%s bottomRightStage=%s",
+                layout.getBounds1(), layout.getBounds2());
+        return updated;
     }
 
     void updateSurfaceBounds(@Nullable SplitLayout layout, @NonNull SurfaceControl.Transaction t,
@@ -2291,6 +2368,9 @@
         (layout != null ? layout : mSplitLayout).applySurfaceChanges(t, topLeftStage.mRootLeash,
                 bottomRightStage.mRootLeash, topLeftStage.mDimLayer, bottomRightStage.mDimLayer,
                 applyResizingOffset);
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+                "updateSurfaceBounds: topLeftStage=%s bottomRightStage=%s",
+                layout.getBounds1(), layout.getBounds2());
     }
 
     @Override
@@ -2329,6 +2409,8 @@
 
     @Override
     public void setLayoutOffsetTarget(int offsetX, int offsetY, SplitLayout layout) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "setLayoutOffsetTarget: x=%d y=%d",
+                offsetX, offsetY);
         final StageTaskListener topLeftStage =
                 mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
         final StageTaskListener bottomRightStage =
@@ -2343,6 +2425,7 @@
         if (displayId != DEFAULT_DISPLAY) {
             return;
         }
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onDisplayAdded: display=%d", displayId);
         mDisplayController.addDisplayChangingController(this::onDisplayChange);
     }
 
@@ -2357,8 +2440,14 @@
 
     private void onDisplayChange(int displayId, int fromRotation, int toRotation,
             @Nullable DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction wct) {
-        if (displayId != DEFAULT_DISPLAY || !mMainStage.isActive()) return;
+        if (displayId != DEFAULT_DISPLAY || !mMainStage.isActive()) {
+            return;
+        }
 
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+                "onDisplayChange: display=%d fromRot=%d toRot=%d config=%s",
+                displayId, fromRotation, toRotation,
+                newDisplayAreaInfo != null ? newDisplayAreaInfo.configuration : null);
         mSplitLayout.rotateTo(toRotation);
         if (newDisplayAreaInfo != null) {
             mSplitLayout.updateConfiguration(newDisplayAreaInfo.configuration);
@@ -2369,6 +2458,7 @@
 
     @VisibleForTesting
     void onFoldedStateChanged(boolean folded) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onFoldedStateChanged: folded=%b", folded);
         mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
         if (!folded) return;
 
@@ -2439,6 +2529,8 @@
         final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
         if (triggerTask == null) {
             if (isSplitActive()) {
+                ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "handleRequest: transition=%d display rotation",
+                        request.getDebugId());
                 // Check if the display is rotating.
                 final TransitionRequestInfo.DisplayChange displayChange =
                         request.getDisplayChange();
@@ -2467,6 +2559,8 @@
         }
 
         if (isSplitActive()) {
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "handleRequest: transition=%d split active",
+                    request.getDebugId());
             // Try to handle everything while in split-screen, so return a WCT even if it's empty.
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  split is active so using split"
                             + "Transition to handle request. triggerTask=%d type=%s mainChildren=%d"
@@ -2541,6 +2635,8 @@
             return null;
         } else {
             if (isOpening && getStageOfTask(triggerTask) != null) {
+                ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "handleRequest: transition=%d enter split",
+                        request.getDebugId());
                 // One task is appearing into split, prepare to enter split screen.
                 out = new WindowContainerTransaction();
                 prepareEnterSplitScreen(out);
@@ -2557,6 +2653,8 @@
      */
     public void addEnterOrExitIfNeeded(@Nullable TransitionRequestInfo request,
             @NonNull WindowContainerTransaction outWCT) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "addEnterOrExitIfNeeded: transition=%d",
+                request.getDebugId());
         final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
         if (triggerTask != null && triggerTask.displayId != mDisplayId) {
             // Skip handling task on the other display.
@@ -2591,6 +2689,7 @@
     public void mergeAnimation(IBinder transition, TransitionInfo info,
             SurfaceControl.Transaction t, IBinder mergeTarget,
             Transitions.TransitionFinishCallback finishCallback) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "mergeAnimation: transition=%d", info.getDebugId());
         mSplitTransitions.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
     }
 
@@ -2602,6 +2701,7 @@
     @Override
     public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted,
             @Nullable SurfaceControl.Transaction finishT) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTransitionConsumed");
         mSplitTransitions.onTransitionConsumed(transition, aborted, finishT);
     }
 
@@ -2617,6 +2717,7 @@
             // If we're not in split-mode, just abort so something else can handle it.
             if (!mMainStage.isActive()) return false;
 
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "startAnimation: transition=%d", info.getDebugId());
             mSplitLayout.setFreezeDividerWindow(false);
             final StageChangeRecord record = new StageChangeRecord();
             final int transitType = info.getType();
@@ -2727,6 +2828,8 @@
             if (mMixedHandler.animatePendingSplitWithDisplayChange(transition, info,
                     startTransaction, finishTransaction, finishCallback)) {
                 if (mSplitTransitions.isPendingResize(transition)) {
+                    ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+                            "startAnimation: transition=%d display change", info.getDebugId());
                     // Only need to update in resize because divider exist before transition.
                     mSplitLayout.update(startTransaction, true /* resetImePosition */);
                     startTransaction.apply();
@@ -2797,6 +2900,8 @@
             @NonNull SurfaceControl.Transaction startTransaction,
             @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "startPendingAnimation: transition=%d",
+                info.getDebugId());
         boolean shouldAnimate = true;
         if (mSplitTransitions.isPendingEnter(transition)) {
             shouldAnimate = startPendingEnterAnimation(transition,
@@ -2830,6 +2935,7 @@
 
     /** Called to clean-up state and do house-keeping after the animation is done. */
     public void onTransitionAnimationComplete() {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTransitionAnimationComplete");
         // If still playing, let it finish.
         if (!mMainStage.isActive() && !mIsExiting) {
             // Update divider state after animation so that it is still around and positioned
@@ -2842,6 +2948,8 @@
             @NonNull SplitScreenTransitions.EnterSession enterTransition,
             @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t,
             @NonNull SurfaceControl.Transaction finishT) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "startPendingEnterAnimation: enterTransition=%s",
+                enterTransition);
         // First, verify that we actually have opened apps in both splits.
         TransitionInfo.Change mainChild = null;
         TransitionInfo.Change sideChild = null;
@@ -2959,6 +3067,7 @@
     }
 
     public void goToFullscreenFromSplit() {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "goToFullscreenFromSplit");
         // If main stage is focused, toEnd = true if
         // mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT. Otherwise toEnd = false
         // If side stage is focused, toEnd = true if
@@ -2974,6 +3083,7 @@
 
     /** Move the specified task to fullscreen, regardless of focus state. */
     public void moveTaskToFullscreen(int taskId, int exitReason) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "moveTaskToFullscreen");
         boolean leftOrTop;
         if (mMainStage.containsTask(taskId)) {
             leftOrTop = (mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT);
@@ -2994,6 +3104,7 @@
      */
     public void onPipExpandToSplit(WindowContainerTransaction wct,
             ActivityManager.RunningTaskInfo taskInfo) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onPipExpandToSplit: task=%s", taskInfo);
         prepareEnterSplitScreen(wct, taskInfo, getActivateSplitPosition(taskInfo),
                 false /*resizeAnim*/);
 
@@ -3040,6 +3151,9 @@
     public void prepareDismissAnimation(@StageType int toStage, @ExitReason int dismissReason,
             @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t,
             @NonNull SurfaceControl.Transaction finishT) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, 
+                "prepareDismissAnimation: transition=%d toStage=%d reason=%s",
+                info.getDebugId(), toStage, exitReasonToString(dismissReason));
         // Make some noise if things aren't totally expected. These states shouldn't effect
         // transitions locally, but remotes (like Launcher) may get confused if they were
         // depending on listener callbacks. This can happen because task-organizer callbacks
@@ -3126,6 +3240,9 @@
             @NonNull SplitScreenTransitions.DismissSession dismissTransition,
             @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t,
             @NonNull SurfaceControl.Transaction finishT) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+                "startPendingDismissAnimation: transition=%d dismissTransition=%s",
+                info.getDebugId(), dismissTransition);
         prepareDismissAnimation(dismissTransition.mDismissTop, dismissTransition.mReason, info,
                 t, finishT);
         if (dismissTransition.mDismissTop == STAGE_TYPE_UNDEFINED) {
@@ -3146,6 +3263,8 @@
 
     /** Call this when starting the open-recents animation while split-screen is active. */
     public void onRecentsInSplitAnimationStart(TransitionInfo info) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onRecentsInSplitAnimationStart: transition=%d",
+                info.getDebugId());
         if (isSplitScreenVisible()) {
             // Cache tasks on live tile.
             for (int i = 0; i < info.getChanges().size(); ++i) {
@@ -3178,6 +3297,7 @@
     /** Call this when the recents animation during split-screen finishes. */
     public void onRecentsInSplitAnimationFinish(WindowContainerTransaction finishWct,
             SurfaceControl.Transaction finishT) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onRecentsInSplitAnimationFinish");
         mPausingTasks.clear();
         // Check if the recent transition is finished by returning to the current
         // split, so we can restore the divider bar.
@@ -3203,6 +3323,7 @@
 
     /** Call this when the recents animation finishes by doing pair-to-pair switch. */
     public void onRecentsPairToPairAnimationFinish(WindowContainerTransaction finishWct) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onRecentsPairToPairAnimationFinish");
         // Pair-to-pair switch happened so here should evict the live tile from its stage.
         // Otherwise, the task will remain in stage, and occluding the new task when next time
         // user entering recents.
@@ -3284,6 +3405,7 @@
      * handled.
      */
     private void setSplitsVisible(boolean visible) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "setSplitsVisible: visible=%b", visible);
         mMainStageListener.mVisible = mSideStageListener.mVisible = visible;
         mMainStageListener.mHasChildren = mSideStageListener.mHasChildren = visible;
     }
@@ -3292,6 +3414,7 @@
      * Sets drag info to be logged when splitscreen is next entered.
      */
     public void onDroppedToSplit(@SplitPosition int position, InstanceId dragSessionId) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onDroppedToSplit: position=%d", position);
         if (!isSplitScreenVisible()) {
             mIsDropEntering = true;
             mSkipEvictingMainStageChildren = true;
@@ -3308,7 +3431,8 @@
     /**
      * Sets info to be logged when splitscreen is next entered.
      */
-    public void onRequestToSplit(InstanceId sessionId, int enterReason) {
+    public void onRequestToSplit(InstanceId sessionId, @SplitEnterReason int enterReason) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onRequestToSplit: reason=%d", enterReason);
         if (!isSplitScreenVisible() && !ENABLE_SHELL_TRANSITIONS) {
             // If split running background, exit split first.
             // Skip this on shell transition due to we could evict existing tasks on transition
@@ -3384,6 +3508,7 @@
 
         @Override
         public void onNoLongerSupportMultiWindow(ActivityManager.RunningTaskInfo taskInfo) {
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onNoLongerSupportMultiWindow: task=%s", taskInfo);
             if (mMainStage.isActive()) {
                 final boolean isMainStage = mMainStageListener == this;
                 if (!ENABLE_SHELL_TRANSITIONS) {
@@ -3393,15 +3518,24 @@
                     return;
                 }
 
-                final int stageType = isMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+                // If visible, we preserve the app and keep it running. If an app becomes
+                // unsupported in the bg, break split without putting anything on top
+                boolean splitScreenVisible = isSplitScreenVisible();
+                int stageType = STAGE_TYPE_UNDEFINED;
+                if (splitScreenVisible) {
+                    stageType = isMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+                }
                 final WindowContainerTransaction wct = new WindowContainerTransaction();
                 prepareExitSplitScreen(stageType, wct);
+                clearSplitPairedInRecents(EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
                 mSplitTransitions.startDismissTransition(wct, StageCoordinator.this, stageType,
                         EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
                 Log.w(TAG, splitFailureMessage("onNoLongerSupportMultiWindow",
                         "app package " + taskInfo.baseActivity.getPackageName()
                         + " does not support splitscreen, or is a controlled activity type"));
-                mSplitUnsupportedToast.show();
+                if (splitScreenVisible) {
+                    mSplitUnsupportedToast.show();
+                }
             }
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index af7bf36..f33ab33 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -25,6 +25,7 @@
 import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
 import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;
 import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
 import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
 
 import android.annotation.CallSuper;
@@ -44,6 +45,7 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.ArrayUtils;
 import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.ShellTaskOrganizer;
@@ -175,6 +177,9 @@
     @Override
     @CallSuper
     public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskAppeared: task=%d taskParent=%d rootTask=%d",
+                taskInfo.taskId, taskInfo.parentTaskId,
+                mRootTaskInfo != null ? mRootTaskInfo.taskId : -1);
         if (mRootTaskInfo == null) {
             mRootLeash = leash;
             mRootTaskInfo = taskInfo;
@@ -225,6 +230,9 @@
                     || !ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType())
                     || !ArrayUtils.contains(CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE,
                     taskInfo.getWindowingMode())) {
+                ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+                        "onTaskInfoChanged: task=%d no longer supports multiwindow",
+                        taskInfo.taskId);
                 // Leave split screen if the task no longer supports multi window or have
                 // uncontrolled task.
                 mCallbacks.onNoLongerSupportMultiWindow(taskInfo);
@@ -251,6 +259,7 @@
     @Override
     @CallSuper
     public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskVanished: task=%d", taskInfo.taskId);
         final int taskId = taskInfo.taskId;
         if (mRootTaskInfo.taskId == taskId) {
             mCallbacks.onRootTaskVanished();
@@ -333,6 +342,7 @@
     }
 
     void addTask(ActivityManager.RunningTaskInfo task, WindowContainerTransaction wct) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "addTask: task=%d", task.taskId);
         // Clear overridden bounds and windowing mode to make sure the child task can inherit
         // windowing mode and bounds from split root.
         wct.setWindowingMode(task.token, WINDOWING_MODE_UNDEFINED)
@@ -342,6 +352,7 @@
     }
 
     void reorderChild(int taskId, boolean onTop, WindowContainerTransaction wct) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "reorderChild: task=%d onTop=%b", taskId, onTop);
         if (!containsTask(taskId)) {
             return;
         }
@@ -357,6 +368,7 @@
 
     /** Collects all the current child tasks and prepares transaction to evict them to display. */
     void evictAllChildren(WindowContainerTransaction wct) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evicting all children");
         for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
             final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
             wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
@@ -367,11 +379,13 @@
         for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
             final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
             if (taskId == taskInfo.taskId) continue;
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict other child: task=%d", taskId);
             wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
         }
     }
 
     void evictNonOpeningChildren(RemoteAnimationTarget[] apps, WindowContainerTransaction wct) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "evictNonOpeningChildren");
         final SparseArray<ActivityManager.RunningTaskInfo> toBeEvict = mChildrenTaskInfo.clone();
         for (int i = 0; i < apps.length; i++) {
             if (apps[i].mode == MODE_OPENING) {
@@ -380,6 +394,7 @@
         }
         for (int i = toBeEvict.size() - 1; i >= 0; i--) {
             final ActivityManager.RunningTaskInfo taskInfo = toBeEvict.valueAt(i);
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict non-opening child: task=%d", taskInfo.taskId);
             wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
         }
     }
@@ -388,12 +403,15 @@
         for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
             final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
             if (!taskInfo.isVisible) {
+                ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict invisible child: task=%d",
+                        taskInfo.taskId);
                 wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
             }
         }
     }
 
     void evictChildren(WindowContainerTransaction wct, int taskId) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict child: task=%d", taskId);
         final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.get(taskId);
         if (taskInfo != null) {
             wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index bfb60c0..da2965c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -417,7 +417,7 @@
         final SplashViewBuilder builder = new SplashViewBuilder(context, ai);
         final SplashScreenView view = builder
                 .setWindowBGColor(themeBGColor)
-                .chooseStyle(STARTING_WINDOW_TYPE_SPLASH_SCREEN)
+                .chooseStyle(STARTING_WINDOW_TYPE_SOLID_COLOR_SPLASH_SCREEN)
                 .build();
         view.setNotCopyable();
         return view;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index c70a821..9130edf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -470,10 +470,12 @@
                 }
 
                 final float cornerRadius;
-                if (a.hasRoundedCorners() && isTask) {
-                    // hasRoundedCorners is currently only enabled for tasks
+                if (a.hasRoundedCorners()) {
+                    final int displayId = isTask ? change.getTaskInfo().displayId
+                            : info.getRoot(TransitionUtil.rootIndexFor(change, info))
+                                    .getDisplayId();
                     final Context displayContext =
-                            mDisplayController.getDisplayContext(change.getTaskInfo().displayId);
+                            mDisplayController.getDisplayContext(displayId);
                     cornerRadius = displayContext == null ? 0
                             : ScreenDecorationsUtils.getWindowCornerRadius(displayContext);
                 } else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt
index 9b48a54..7a50814 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt
@@ -18,7 +18,7 @@
 
 import android.util.Log
 import com.android.internal.protolog.common.IProtoLogGroup
-import com.android.wm.shell.protolog.ShellProtoLogImpl
+import com.android.internal.protolog.common.ProtoLog
 
 /**
  * Log messages using an API similar to [com.android.internal.protolog.common.ProtoLog]. Useful for
@@ -31,42 +31,42 @@
     companion object {
         /** @see [com.android.internal.protolog.common.ProtoLog.d] */
         fun d(group: IProtoLogGroup, messageString: String, vararg args: Any) {
-            if (ShellProtoLogImpl.isEnabled(group)) {
+            if (ProtoLog.isEnabled(group)) {
                 Log.d(group.tag, String.format(messageString, *args))
             }
         }
 
         /** @see [com.android.internal.protolog.common.ProtoLog.v] */
         fun v(group: IProtoLogGroup, messageString: String, vararg args: Any) {
-            if (ShellProtoLogImpl.isEnabled(group)) {
+            if (ProtoLog.isEnabled(group)) {
                 Log.v(group.tag, String.format(messageString, *args))
             }
         }
 
         /** @see [com.android.internal.protolog.common.ProtoLog.i] */
         fun i(group: IProtoLogGroup, messageString: String, vararg args: Any) {
-            if (ShellProtoLogImpl.isEnabled(group)) {
+            if (ProtoLog.isEnabled(group)) {
                 Log.i(group.tag, String.format(messageString, *args))
             }
         }
 
         /** @see [com.android.internal.protolog.common.ProtoLog.w] */
         fun w(group: IProtoLogGroup, messageString: String, vararg args: Any) {
-            if (ShellProtoLogImpl.isEnabled(group)) {
+            if (ProtoLog.isEnabled(group)) {
                 Log.w(group.tag, String.format(messageString, *args))
             }
         }
 
         /** @see [com.android.internal.protolog.common.ProtoLog.e] */
         fun e(group: IProtoLogGroup, messageString: String, vararg args: Any) {
-            if (ShellProtoLogImpl.isEnabled(group)) {
+            if (ProtoLog.isEnabled(group)) {
                 Log.e(group.tag, String.format(messageString, *args))
             }
         }
 
         /** @see [com.android.internal.protolog.common.ProtoLog.wtf] */
         fun wtf(group: IProtoLogGroup, messageString: String, vararg args: Any) {
-            if (ShellProtoLogImpl.isEnabled(group)) {
+            if (ProtoLog.isEnabled(group)) {
                 Log.wtf(group.tag, String.format(messageString, *args))
             }
         }
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 96eaa1e..91e9601 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
@@ -190,6 +190,7 @@
         mRelayoutParams.mShadowRadiusId = shadowRadiusID;
         mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
         mRelayoutParams.mSetTaskPositionAndCrop = setTaskCropAndPosition;
+        mRelayoutParams.mAllowCaptionInputFallthrough = false;
 
         relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
         // After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 5b8ffb3..f4ccd68 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
@@ -22,13 +22,18 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
+import static android.view.MotionEvent.ACTION_CANCEL;
 import static android.view.MotionEvent.ACTION_HOVER_ENTER;
 import static android.view.MotionEvent.ACTION_HOVER_EXIT;
+import static android.view.MotionEvent.ACTION_UP;
 import static android.view.WindowInsets.Type.statusBars;
 
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE;
+import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR;
+import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR;
+import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR;
+import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR;
 import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION;
 import static com.android.wm.shell.windowdecor.MoveToDesktopAnimator.DRAG_FREEFORM_SCALE;
 
@@ -47,9 +52,13 @@
 import android.hardware.input.InputManager;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
 import android.util.SparseArray;
 import android.view.Choreographer;
 import android.view.GestureDetector;
+import android.view.ISystemGestureExclusionListener;
+import android.view.IWindowManager;
 import android.view.InputChannel;
 import android.view.InputEvent;
 import android.view.InputEventReceiver;
@@ -60,7 +69,6 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
@@ -73,9 +81,11 @@
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
 import com.android.wm.shell.desktopmode.DesktopModeStatus;
+import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
 import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition;
 import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
@@ -88,6 +98,7 @@
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionRegionListener;
+import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
 
 import java.io.PrintWriter;
 import java.util.Optional;
@@ -102,6 +113,8 @@
     private static final String TAG = "DesktopModeWindowDecorViewModel";
 
     private final DesktopModeWindowDecoration.Factory mDesktopModeWindowDecorFactory;
+    private final IWindowManager mWindowManager;
+    private final ShellExecutor mMainExecutor;
     private final ActivityTaskManager mActivityTaskManager;
     private final ShellCommandHandler mShellCommandHandler;
     private final ShellTaskOrganizer mTaskOrganizer;
@@ -111,7 +124,8 @@
     private final Choreographer mMainChoreographer;
     private final DisplayController mDisplayController;
     private final SyncTransactionQueue mSyncQueue;
-    private final Optional<DesktopTasksController> mDesktopTasksController;
+    private final DesktopTasksController mDesktopTasksController;
+    private final InputManager mInputManager;
     private boolean mTransitionDragActive;
 
     private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>();
@@ -119,8 +133,7 @@
     private final ExclusionRegionListener mExclusionRegionListener =
             new ExclusionRegionListenerImpl();
 
-    private final SparseArray<DesktopModeWindowDecoration> mWindowDecorByTaskId =
-            new SparseArray<>();
+    private final SparseArray<DesktopModeWindowDecoration> mWindowDecorByTaskId;
     private final DragStartListenerImpl mDragStartListener = new DragStartListenerImpl();
     private final InputMonitorFactory mInputMonitorFactory;
     private TaskOperations mTaskOperations;
@@ -135,14 +148,31 @@
             new DesktopModeKeyguardChangeListener();
     private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
     private final DisplayInsetsController mDisplayInsetsController;
+    private final Region mExclusionRegion = Region.obtain();
     private boolean mInImmersiveMode;
 
+    private final ISystemGestureExclusionListener mGestureExclusionListener =
+            new ISystemGestureExclusionListener.Stub() {
+                @Override
+                public void onSystemGestureExclusionChanged(int displayId,
+                        Region systemGestureExclusion, Region systemGestureExclusionUnrestricted) {
+                    if (mContext.getDisplayId() != displayId) {
+                        return;
+                    }
+                    mMainExecutor.execute(() -> {
+                        mExclusionRegion.set(systemGestureExclusion);
+                    });
+                }
+            };
+
     public DesktopModeWindowDecorViewModel(
             Context context,
+            ShellExecutor shellExecutor,
             Handler mainHandler,
             Choreographer mainChoreographer,
             ShellInit shellInit,
             ShellCommandHandler shellCommandHandler,
+            IWindowManager windowManager,
             ShellTaskOrganizer taskOrganizer,
             DisplayController displayController,
             ShellController shellController,
@@ -154,10 +184,12 @@
     ) {
         this(
                 context,
+                shellExecutor,
                 mainHandler,
                 mainChoreographer,
                 shellInit,
                 shellCommandHandler,
+                windowManager,
                 taskOrganizer,
                 displayController,
                 shellController,
@@ -168,16 +200,19 @@
                 new DesktopModeWindowDecoration.Factory(),
                 new InputMonitorFactory(),
                 SurfaceControl.Transaction::new,
-                rootTaskDisplayAreaOrganizer);
+                rootTaskDisplayAreaOrganizer,
+                new SparseArray<>());
     }
 
     @VisibleForTesting
     DesktopModeWindowDecorViewModel(
             Context context,
+            ShellExecutor shellExecutor,
             Handler mainHandler,
             Choreographer mainChoreographer,
             ShellInit shellInit,
             ShellCommandHandler shellCommandHandler,
+            IWindowManager windowManager,
             ShellTaskOrganizer taskOrganizer,
             DisplayController displayController,
             ShellController shellController,
@@ -188,8 +223,10 @@
             DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory,
             InputMonitorFactory inputMonitorFactory,
             Supplier<SurfaceControl.Transaction> transactionFactory,
-            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
+            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+            SparseArray<DesktopModeWindowDecoration> windowDecorByTaskId) {
         mContext = context;
+        mMainExecutor = shellExecutor;
         mMainHandler = mainHandler;
         mMainChoreographer = mainChoreographer;
         mActivityTaskManager = mContext.getSystemService(ActivityTaskManager.class);
@@ -199,12 +236,15 @@
         mDisplayInsetsController = displayInsetsController;
         mSyncQueue = syncQueue;
         mTransitions = transitions;
-        mDesktopTasksController = desktopTasksController;
+        mDesktopTasksController = desktopTasksController.get();
         mShellCommandHandler = shellCommandHandler;
+        mWindowManager = windowManager;
         mDesktopModeWindowDecorFactory = desktopModeWindowDecorFactory;
         mInputMonitorFactory = inputMonitorFactory;
         mTransactionFactory = transactionFactory;
         mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
+        mInputManager = mContext.getSystemService(InputManager.class);
+        mWindowDecorByTaskId = windowDecorByTaskId;
 
         shellInit.addInitCallback(this::onInit, this);
     }
@@ -214,8 +254,14 @@
         mShellCommandHandler.addDumpCallback(this::dump, this);
         mDisplayInsetsController.addInsetsChangedListener(mContext.getDisplayId(),
                 new DesktopModeOnInsetsChangedListener());
-        mDesktopTasksController.ifPresent(c -> c.setOnTaskResizeAnimationListener(
-                new DeskopModeOnTaskResizeAnimationListener()));
+        mDesktopTasksController.setOnTaskResizeAnimationListener(
+                new DeskopModeOnTaskResizeAnimationListener());
+        try {
+            mWindowManager.registerSystemGestureExclusionListener(mGestureExclusionListener,
+                    mContext.getDisplayId());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to register window manager callbacks", e);
+        }
     }
 
     @Override
@@ -233,7 +279,7 @@
                     DesktopModeWindowDecoration decor = mWindowDecorByTaskId.get(taskId);
                     if (decor != null && DesktopModeStatus.isEnabled()
                             && decor.mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
-                        mDesktopTasksController.ifPresent(c -> c.moveToSplit(decor.mTaskInfo));
+                        mDesktopTasksController.moveToSplit(decor.mTaskInfo);
                     }
                 }
             }
@@ -300,8 +346,7 @@
 
     @Override
     public void destroyWindowDecoration(RunningTaskInfo taskInfo) {
-        final DesktopModeWindowDecoration decoration =
-                mWindowDecorByTaskId.removeReturnOld(taskInfo.taskId);
+        final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
         if (decoration == null) return;
 
         decoration.close();
@@ -309,21 +354,32 @@
         if (mEventReceiversByDisplay.contains(displayId)) {
             removeTaskFromEventReceiver(displayId);
         }
+        // Remove the decoration from the cache last because WindowDecoration#close could still
+        // issue CANCEL MotionEvents to touch listeners before its view host is released.
+        // See b/327664694.
+        mWindowDecorByTaskId.remove(taskInfo.taskId);
     }
 
     private class DesktopModeTouchEventListener extends GestureDetector.SimpleOnGestureListener
             implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener,
             View.OnGenericMotionListener , DragDetector.MotionEventHandler {
         private static final int CLOSE_MAXIMIZE_MENU_DELAY_MS = 150;
+
         private final int mTaskId;
         private final WindowContainerToken mTaskToken;
         private final DragPositioningCallback mDragPositioningCallback;
         private final DragDetector mDragDetector;
         private final GestureDetector mGestureDetector;
 
+        /**
+         * Whether to pilfer the next motion event to send cancellations to the windows below.
+         * Useful when the caption window is spy and the gesture should be handle by the system
+         * instead of by the app for their custom header content.
+         */
+        private boolean mShouldPilferCaptionEvents;
         private boolean mIsDragging;
+        private boolean mTouchscreenInUse;
         private boolean mHasLongClicked;
-        private boolean mShouldClick;
         private int mDragPointerId = -1;
         private final Runnable mCloseMaximizeWindowRunnable;
 
@@ -344,6 +400,10 @@
 
         @Override
         public void onClick(View v) {
+            if (mIsDragging) {
+                mIsDragging = false;
+                return;
+            }
             final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
             final int id = v.getId();
             if (id == R.id.close_window) {
@@ -363,14 +423,11 @@
                     decoration.closeHandleMenu();
                 }
             } else if (id == R.id.desktop_button) {
-                if (mDesktopTasksController.isPresent()) {
-                    final WindowContainerTransaction wct = new WindowContainerTransaction();
-                    // App sometimes draws before the insets from WindowDecoration#relayout have
-                    // been added, so they must be added here
-                    mWindowDecorByTaskId.get(mTaskId).addCaptionInset(wct);
-                    mDesktopTasksController.get().moveToDesktop(mTaskId, wct);
-                    closeOtherSplitTask(mTaskId);
-                }
+                final WindowContainerTransaction wct = new WindowContainerTransaction();
+                // App sometimes draws before the insets from WindowDecoration#relayout have
+                // been added, so they must be added here
+                mWindowDecorByTaskId.get(mTaskId).addCaptionInset(wct);
+                mDesktopTasksController.moveToDesktop(mTaskId, wct);
                 decoration.closeHandleMenu();
             } else if (id == R.id.fullscreen_button) {
                 decoration.closeHandleMenu();
@@ -378,42 +435,37 @@
                     mSplitScreenController.moveTaskToFullscreen(mTaskId,
                             SplitScreenController.EXIT_REASON_DESKTOP_MODE);
                 } else {
-                    mDesktopTasksController.ifPresent(c ->
-                            c.moveToFullscreen(mTaskId));
+                    mDesktopTasksController.moveToFullscreen(mTaskId);
                 }
             } else if (id == R.id.split_screen_button) {
                 decoration.closeHandleMenu();
-                mDesktopTasksController.ifPresent(c -> {
-                    c.requestSplit(decoration.mTaskInfo);
-                });
+                mDesktopTasksController.requestSplit(decoration.mTaskInfo);
             } else if (id == R.id.collapse_menu_button) {
                 decoration.closeHandleMenu();
             } else if (id == R.id.select_button) {
                 if (DesktopModeStatus.IS_DISPLAY_CHANGE_ENABLED) {
                     // TODO(b/278084491): dev option to enable display switching
                     //  remove when select is implemented
-                    mDesktopTasksController.ifPresent(c -> c.moveToNextDisplay(mTaskId));
+                    mDesktopTasksController.moveToNextDisplay(mTaskId);
                 }
             } else if (id == R.id.maximize_window) {
                 final RunningTaskInfo taskInfo = decoration.mTaskInfo;
                 decoration.closeHandleMenu();
                 decoration.closeMaximizeMenu();
-                mDesktopTasksController.ifPresent(c -> c.toggleDesktopTaskSize(taskInfo));
+                mDesktopTasksController.toggleDesktopTaskSize(taskInfo);
             } else if (id == R.id.maximize_menu_maximize_button) {
                 final RunningTaskInfo taskInfo = decoration.mTaskInfo;
-                mDesktopTasksController.ifPresent(c -> c.toggleDesktopTaskSize(taskInfo));
+                mDesktopTasksController.toggleDesktopTaskSize(taskInfo);
                 decoration.closeHandleMenu();
                 decoration.closeMaximizeMenu();
             } else if (id == R.id.maximize_menu_snap_left_button) {
                 final RunningTaskInfo taskInfo = decoration.mTaskInfo;
-                mDesktopTasksController.ifPresent(c -> c.snapToHalfScreen(
-                        taskInfo, SnapPosition.LEFT));
+                mDesktopTasksController.snapToHalfScreen(taskInfo, SnapPosition.LEFT);
                 decoration.closeHandleMenu();
                 decoration.closeMaximizeMenu();
             } else if (id == R.id.maximize_menu_snap_right_button) {
                 final RunningTaskInfo taskInfo = decoration.mTaskInfo;
-                mDesktopTasksController.ifPresent(c -> c.snapToHalfScreen(
-                        taskInfo, SnapPosition.RIGHT));
+                mDesktopTasksController.snapToHalfScreen(taskInfo, SnapPosition.RIGHT);
                 decoration.closeHandleMenu();
                 decoration.closeMaximizeMenu();
             }
@@ -422,6 +474,10 @@
         @Override
         public boolean onTouch(View v, MotionEvent e) {
             final int id = v.getId();
+            if ((e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN) {
+                mTouchscreenInUse = e.getActionMasked() != ACTION_UP
+                        && e.getActionMasked() != ACTION_CANCEL;
+            }
             if (id != R.id.caption_handle && id != R.id.desktop_mode_caption
                     && id != R.id.open_menu_button && id != R.id.close_window
                     && id != R.id.maximize_window) {
@@ -430,34 +486,56 @@
             final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
             moveTaskToFront(decoration.mTaskInfo);
 
+            final int actionMasked = e.getActionMasked();
+            final boolean isDown = actionMasked == MotionEvent.ACTION_DOWN;
+            final boolean isUpOrCancel = actionMasked == MotionEvent.ACTION_CANCEL
+                    || actionMasked == MotionEvent.ACTION_UP;
+            if (isDown) {
+                final boolean downInCustomizableCaptionRegion =
+                        decoration.checkTouchEventInCustomizableRegion(e);
+                final boolean downInExclusionRegion = mExclusionRegion.contains(
+                        (int) e.getRawX(), (int) e.getRawY());
+                final boolean isTransparentCaption =
+                        TaskInfoKt.isTransparentCaptionBarAppearance(decoration.mTaskInfo);
+                // The caption window may be a spy window when the caption background is
+                // transparent, which means events will fall through to the app window. Make
+                // sure to cancel these events if they do not happen in the intersection of the
+                // customizable region and what the app reported as exclusion areas, because
+                // the drag-move or other caption gestures should take priority outside those
+                // regions.
+                mShouldPilferCaptionEvents = !(downInCustomizableCaptionRegion
+                        && downInExclusionRegion && isTransparentCaption);
+            }
+
+            if (!mShouldPilferCaptionEvents) {
+                // The event will be handled by a window below.
+                return false;
+            }
+            // Otherwise pilfer so that windows below receive cancellations for this gesture, and
+            // continue normal handling as a caption gesture.
+            if (mInputManager != null) {
+                mInputManager.pilferPointers(v.getViewRootImpl().getInputToken());
+            }
+            if (isUpOrCancel) {
+                // Gesture is finished, reset state.
+                mShouldPilferCaptionEvents = false;
+            }
             if (!mHasLongClicked && id != R.id.maximize_window) {
                 decoration.closeMaximizeMenuIfNeeded(e);
             }
-
-            final long eventDuration = e.getEventTime() - e.getDownTime();
-            final boolean isTouchScreen =
-                    (e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN;
-            final boolean shouldLongClick = isTouchScreen && id == R.id.maximize_window
-                    && !mIsDragging && !mHasLongClicked
-                    && eventDuration >= ViewConfiguration.getLongPressTimeout();
-            if (shouldLongClick) {
-                v.performLongClick();
-                mHasLongClicked = true;
-                return true;
-            }
-
             return mDragDetector.onMotionEvent(v, e);
         }
 
         @Override
         public boolean onLongClick(View v) {
             final int id = v.getId();
-            if (id == R.id.maximize_window) {
+            if (id == R.id.maximize_window && mTouchscreenInUse) {
                 final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
                 moveTaskToFront(decoration.mTaskInfo);
                 if (decoration.isMaximizeMenuActive()) {
                     decoration.closeMaximizeMenu();
                 } else {
+                    mHasLongClicked = true;
                     decoration.createMaximizeMenu();
                 }
                 return true;
@@ -482,8 +560,7 @@
             } else if (ev.getAction() == ACTION_HOVER_EXIT) {
                 if (!decoration.isMaximizeMenuActive() && id == R.id.maximize_window) {
                     decoration.onMaximizeWindowHoverExit();
-                } else if (id == R.id.maximize_window
-                        || MaximizeMenu.Companion.isMaximizeMenuView(id)) {
+                } else if (id == R.id.maximize_window || id == R.id.maximize_menu) {
                     // Close menu if not hovering over maximize menu or maximize button after a
                     // delay to give user a chance to re-enter view or to move from one maximize
                     // menu view to another.
@@ -497,7 +574,7 @@
 
         private void moveTaskToFront(RunningTaskInfo taskInfo) {
             if (!taskInfo.isFocused) {
-                mDesktopTasksController.ifPresent(c -> c.moveTaskToFront(taskInfo));
+                mDesktopTasksController.moveTaskToFront(taskInfo);
             }
         }
 
@@ -516,11 +593,9 @@
             if (mGestureDetector.onTouchEvent(e)) {
                 return true;
             }
-            if (e.getActionMasked() == MotionEvent.ACTION_CANCEL) {
-                // If a motion event is cancelled, reset mShouldClick so a click is not accidentally
-                // performed.
-                mShouldClick = false;
-            }
+            final int id = v.getId();
+            final boolean touchingButton = (id == R.id.close_window || id == R.id.maximize_window
+                    || id == R.id.open_menu_button);
             switch (e.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN: {
                     mDragPointerId = e.getPointerId(0);
@@ -528,12 +603,12 @@
                             0 /* ctrlType */, e.getRawX(0),
                             e.getRawY(0));
                     mIsDragging = false;
-                    mShouldClick = true;
                     mHasLongClicked = false;
-                    return true;
+                    // Do not consume input event if a button is touched, otherwise it would
+                    // prevent the button's ripple effect from showing.
+                    return !touchingButton;
                 }
                 case MotionEvent.ACTION_MOVE: {
-                    mShouldClick = false;
                     // If a decor's resize drag zone is active, don't also try to reposition it.
                     if (decoration.isHandlingDragResize()) break;
                     decoration.closeMaximizeMenu();
@@ -543,10 +618,10 @@
                     final int dragPointerIdx = e.findPointerIndex(mDragPointerId);
                     final Rect newTaskBounds = mDragPositioningCallback.onDragPositioningMove(
                             e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
-                    mDesktopTasksController.ifPresent(c -> c.onDragPositioningMove(taskInfo,
+                    mDesktopTasksController.onDragPositioningMove(taskInfo,
                             decoration.mTaskSurface,
                             e.getRawX(dragPointerIdx),
-                            newTaskBounds));
+                            newTaskBounds);
                     mIsDragging = true;
                     return true;
                 }
@@ -554,11 +629,6 @@
                 case MotionEvent.ACTION_CANCEL: {
                     final boolean wasDragging = mIsDragging;
                     if (!wasDragging) {
-                        if (mShouldClick && v != null && !mHasLongClicked) {
-                            v.performClick();
-                            mShouldClick = false;
-                            return true;
-                        }
                         return false;
                     }
                     if (e.findPointerIndex(mDragPointerId) == -1) {
@@ -573,12 +643,18 @@
                             (int) (e.getRawY(dragPointerIdx) - e.getY(dragPointerIdx)));
                     final Rect newTaskBounds = mDragPositioningCallback.onDragPositioningEnd(
                             e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
-                    mDesktopTasksController.ifPresent(c -> c.onDragPositioningEnd(taskInfo,
-                            position,
+                    mDesktopTasksController.onDragPositioningEnd(taskInfo, position,
                             new PointF(e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)),
-                            newTaskBounds));
-                    mIsDragging = false;
-                    return true;
+                            newTaskBounds);
+                    if (touchingButton && !mHasLongClicked) {
+                        // We need the input event to not be consumed here to end the ripple
+                        // effect on the touched button. We will reset drag state in the ensuing
+                        // onClick call that results.
+                        return false;
+                    } else {
+                        mIsDragging = false;
+                        return true;
+                    }
                 }
             }
             return true;
@@ -597,10 +673,8 @@
                     && action != MotionEvent.ACTION_CANCEL)) {
                 return false;
             }
-            mDesktopTasksController.ifPresent(c -> {
-                final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
-                c.toggleDesktopTaskSize(decoration.mTaskInfo);
-            });
+            final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
+            mDesktopTasksController.toggleDesktopTaskSize(decoration.mTaskInfo);
             return true;
         }
     }
@@ -764,20 +838,29 @@
                     return;
                 }
                 if (mTransitionDragActive) {
+                    final DesktopModeVisualIndicator.IndicatorType indicatorType =
+                            mDesktopTasksController.updateVisualIndicator(relevantDecor.mTaskInfo,
+                                    relevantDecor.mTaskSurface, ev.getRawX(), ev.getRawY());
                     mTransitionDragActive = false;
-                    final int statusBarHeight = getStatusBarHeight(
-                            relevantDecor.mTaskInfo.displayId);
-                    if (ev.getRawY() > 2 * statusBarHeight) {
+                    if (indicatorType == TO_DESKTOP_INDICATOR
+                            || indicatorType == TO_SPLIT_LEFT_INDICATOR
+                            || indicatorType == TO_SPLIT_RIGHT_INDICATOR) {
                         if (DesktopModeStatus.isEnabled()) {
                             animateToDesktop(relevantDecor, ev);
                         }
                         mMoveToDesktopAnimator = null;
                         return;
                     } else if (mMoveToDesktopAnimator != null) {
-                        mDesktopTasksController.ifPresent(
-                                c -> c.cancelDragToDesktop(relevantDecor.mTaskInfo));
+                        mDesktopTasksController.onDragPositioningEndThroughStatusBar(
+                                new PointF(ev.getRawX(), ev.getRawY()),
+                                relevantDecor.mTaskInfo,
+                                calculateFreeformBounds(ev.getDisplayId(), DRAG_FREEFORM_SCALE));
                         mMoveToDesktopAnimator = null;
                         return;
+                    } else {
+                        // In cases where we create an indicator but do not start the
+                        // move-to-desktop animation, we need to dismiss it.
+                        mDesktopTasksController.releaseVisualIndicator();
                     }
                 }
                 relevantDecor.checkClickEvent(ev);
@@ -789,20 +872,17 @@
                     return;
                 }
                 if (mTransitionDragActive) {
-                    mDesktopTasksController.ifPresent(
-                            c -> c.updateVisualIndicator(
+                    final DesktopModeVisualIndicator.IndicatorType indicatorType =
+                            mDesktopTasksController.updateVisualIndicator(
                                     relevantDecor.mTaskInfo,
-                                    relevantDecor.mTaskSurface, ev.getRawX(), ev.getRawY()));
-                    final int statusBarHeight = getStatusBarHeight(
-                            relevantDecor.mTaskInfo.displayId);
-                    if (ev.getRawY() > statusBarHeight) {
+                                    relevantDecor.mTaskSurface, ev.getRawX(), ev.getRawY());
+                    if (indicatorType != TO_FULLSCREEN_INDICATOR) {
                         if (mMoveToDesktopAnimator == null) {
                             mMoveToDesktopAnimator = new MoveToDesktopAnimator(
                                     mContext, mDragToDesktopAnimationStartBounds,
                                     relevantDecor.mTaskInfo, relevantDecor.mTaskSurface);
-                            mDesktopTasksController.ifPresent(
-                                    c -> c.startDragToDesktop(relevantDecor.mTaskInfo,
-                                            mMoveToDesktopAnimator));
+                            mDesktopTasksController.startDragToDesktop(relevantDecor.mTaskInfo,
+                                    mMoveToDesktopAnimator);
                         }
                     }
                     if (mMoveToDesktopAnimator != null) {
@@ -824,16 +904,16 @@
      * @param scale the amount to scale to relative to the Screen Bounds
      */
     private Rect calculateFreeformBounds(int displayId, float scale) {
+        // TODO(b/319819547): Account for app constraints so apps do not become letterboxed
         final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(displayId);
         final int screenWidth = displayLayout.width();
         final int screenHeight = displayLayout.height();
 
         final float adjustmentPercentage = (1f - scale) / 2;
-        final Rect endBounds = new Rect((int) (screenWidth * adjustmentPercentage),
+        return new Rect((int) (screenWidth * adjustmentPercentage),
                 (int) (screenHeight * adjustmentPercentage),
                 (int) (screenWidth * (adjustmentPercentage + scale)),
                 (int) (screenHeight * (adjustmentPercentage + scale)));
-        return endBounds;
     }
 
     /**
@@ -848,6 +928,8 @@
      * Animates a window to the center, grows to freeform size, and transitions to Desktop Mode.
      * @param relevantDecor the window decor of the task to be animated
      * @param ev the motion event that triggers the animation
+     * TODO(b/315527000): This animation needs to be adjusted to allow snap left/right cases.
+     *  Currently fullscreen -> split snap still animates to center screen before readjusting.
      */
     private void centerAndMoveToDesktopWithAnimation(DesktopModeWindowDecoration relevantDecor,
             MotionEvent ev) {
@@ -871,12 +953,12 @@
         animator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
-                mDesktopTasksController.ifPresent(
-                        c -> {
-                            c.onDragPositioningEndThroughStatusBar(relevantDecor.mTaskInfo,
-                                    calculateFreeformBounds(ev.getDisplayId(),
-                                            FINAL_FREEFORM_SCALE));
-                        });
+                mDesktopTasksController.onDragPositioningEndThroughStatusBar(
+                        new PointF(ev.getRawX(), ev.getRawY()),
+                        relevantDecor.mTaskInfo,
+                        calculateFreeformBounds(ev.getDisplayId(),
+                                DesktopTasksController
+                                        .DESKTOP_MODE_INITIAL_BOUNDS_SCALE));
             }
         });
         animator.start();
@@ -1006,7 +1088,7 @@
 
         final DragPositioningCallback dragPositioningCallback;
         final int transitionAreaHeight = mContext.getResources().getDimensionPixelSize(
-                R.dimen.desktop_mode_transition_area_height);
+                R.dimen.desktop_mode_fullscreen_from_desktop_height);
         if (!DesktopModeStatus.isVeiledResizeEnabled()) {
             dragPositioningCallback =  new FluidResizeTaskPositioner(
                     mTaskOrganizer, mTransitions, windowDecoration, mDisplayController,
@@ -1041,12 +1123,6 @@
         return mSplitScreenController.getTaskInfo(remainingTaskPosition);
     }
 
-    private void closeOtherSplitTask(int taskId) {
-        if (isTaskInSplitScreen(taskId)) {
-            mTaskOperations.closeTask(getOtherSplitTask(taskId).token);
-        }
-    }
-
     private boolean isTaskInSplitScreen(int taskId) {
         return mSplitScreenController != null
                 && mSplitScreenController.isTaskInSplitScreen(taskId);
@@ -1111,12 +1187,12 @@
 
         @Override
         public void onExclusionRegionChanged(int taskId, Region region) {
-            mDesktopTasksController.ifPresent(d -> d.onExclusionRegionChanged(taskId, region));
+            mDesktopTasksController.onExclusionRegionChanged(taskId, region);
         }
 
         @Override
         public void onExclusionRegionDismissed(int taskId) {
-            mDesktopTasksController.ifPresent(d -> d.removeExclusionRegionForTask(taskId));
+            mDesktopTasksController.removeExclusionRegionForTask(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 74f460b..39803e2 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
@@ -56,6 +56,7 @@
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
+import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
 import com.android.wm.shell.windowdecor.viewholder.DesktopModeAppControlsWindowDecorationViewHolder;
 import com.android.wm.shell.windowdecor.viewholder.DesktopModeFocusedWindowDecorationViewHolder;
 import com.android.wm.shell.windowdecor.viewholder.DesktopModeWindowDecorationViewHolder;
@@ -317,24 +318,23 @@
         relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode());
         relayoutParams.mCaptionWidthId = getCaptionWidthId(relayoutParams.mLayoutResId);
 
-        // The "app controls" type caption bar should report the occluding elements as bounding
-        // rects to the insets system so that apps can draw in the empty space left in the center.
-        if (captionLayoutId == R.layout.desktop_mode_app_controls_window_decor) {
-            // The "app chip" section of the caption bar, it's aligned to the left and its width
-            // varies depending on the length of the app name, but we'll report its max width for
-            // now.
-            // TODO(b/316387515): consider reporting the true width after it's been laid out.
+        if (captionLayoutId == R.layout.desktop_mode_app_controls_window_decor
+                && TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo)) {
+            // App is requesting to customize the caption bar. Allow input to fall through to the
+            // windows below so that the app can respond to input events on their custom content.
+            relayoutParams.mAllowCaptionInputFallthrough = true;
+            // Report occluding elements as bounding rects to the insets system so that apps can
+            // draw in the empty space in the center:
+            //   First, the "app chip" section of the caption bar (+ some extra margins).
             final RelayoutParams.OccludingCaptionElement appChipElement =
                     new RelayoutParams.OccludingCaptionElement();
-            appChipElement.mWidthResId = R.dimen.desktop_mode_app_details_max_width;
+            appChipElement.mWidthResId = R.dimen.desktop_mode_customizable_caption_margin_start;
             appChipElement.mAlignment = RelayoutParams.OccludingCaptionElement.Alignment.START;
             relayoutParams.mOccludingCaptionElements.add(appChipElement);
-            // The "controls" section of the caption bar (maximize, close btns). These are aligned
-            // to the right of the caption bar and have a fixed width.
-            // TODO(b/316387515): add additional padding for an exclusive drag-move region.
+            //   Then, the right-aligned section (drag space, maximize and close buttons).
             final RelayoutParams.OccludingCaptionElement controlsElement =
                     new RelayoutParams.OccludingCaptionElement();
-            controlsElement.mWidthResId = R.dimen.desktop_mode_right_edge_buttons_width;
+            controlsElement.mWidthResId = R.dimen.desktop_mode_customizable_caption_margin_end;
             controlsElement.mAlignment = RelayoutParams.OccludingCaptionElement.Alignment.END;
             relayoutParams.mOccludingCaptionElements.add(controlsElement);
         }
@@ -699,6 +699,13 @@
     }
 
     /**
+     * Checks whether the touch event falls inside the customizable caption region.
+     */
+    boolean checkTouchEventInCustomizableRegion(MotionEvent ev) {
+        return mResult.mCustomizableCaptionRegion.contains((int) ev.getRawX(), (int) ev.getRawY());
+    }
+
+    /**
      * 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)
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 dc65855..32c2d1e 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
@@ -31,6 +31,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.os.Binder;
 import android.view.Display;
 import android.view.InsetsSource;
@@ -311,6 +312,10 @@
                 if (numOfElements == 0) {
                     boundingRects = null;
                 } else {
+                    // The customizable region can at most be equal to the caption bar.
+                    if (params.mAllowCaptionInputFallthrough) {
+                        outResult.mCustomizableCaptionRegion.set(mCaptionInsetsRect);
+                    }
                     boundingRects = new Rect[numOfElements];
                     for (int i = 0; i < numOfElements; i++) {
                         final OccludingCaptionElement element =
@@ -319,9 +324,14 @@
                                 resources.getDimensionPixelSize(element.mWidthResId);
                         boundingRects[i] =
                                 calculateBoundingRect(element, elementWidthPx, mCaptionInsetsRect);
+                        // Subtract the regions used by the caption elements, the rest is
+                        // customizable.
+                        if (params.mAllowCaptionInputFallthrough) {
+                            outResult.mCustomizableCaptionRegion.op(boundingRects[i],
+                                    Region.Op.DIFFERENCE);
+                        }
                     }
                 }
-
                 // Add this caption as an inset source.
                 wct.addInsetsSource(mTaskInfo.token,
                         mOwner, 0 /* index */, WindowInsets.Type.captionBar(), mCaptionInsetsRect,
@@ -389,6 +399,11 @@
                         WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
         lp.setTitle("Caption of Task=" + mTaskInfo.taskId);
         lp.setTrustedOverlay();
+        if (params.mAllowCaptionInputFallthrough) {
+            lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_SPY;
+        } else {
+            lp.inputFeatures &= ~WindowManager.LayoutParams.INPUT_FEATURE_SPY;
+        }
         if (mViewHost == null) {
             mViewHost = mSurfaceControlViewHostFactory.create(mDecorWindowContext, mDisplay,
                     mCaptionWindowManager);
@@ -596,6 +611,7 @@
         int mCaptionHeightId;
         int mCaptionWidthId;
         final List<OccludingCaptionElement> mOccludingCaptionElements = new ArrayList<>();
+        boolean mAllowCaptionInputFallthrough;
 
         int mShadowRadiusId;
         int mCornerRadius;
@@ -610,6 +626,7 @@
             mCaptionHeightId = Resources.ID_NULL;
             mCaptionWidthId = Resources.ID_NULL;
             mOccludingCaptionElements.clear();
+            mAllowCaptionInputFallthrough = false;
 
             mShadowRadiusId = Resources.ID_NULL;
             mCornerRadius = 0;
@@ -637,6 +654,7 @@
         int mCaptionHeight;
         int mCaptionWidth;
         int mCaptionX;
+        final Region mCustomizableCaptionRegion = Region.obtain();
         int mWidth;
         int mHeight;
         T mRootView;
@@ -647,6 +665,7 @@
             mCaptionHeight = 0;
             mCaptionWidth = 0;
             mCaptionX = 0;
+            mCustomizableCaptionRegion.setEmpty();
             mRootView = null;
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/extension/TaskInfo.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/extension/TaskInfo.kt
new file mode 100644
index 0000000..5dd96ac
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/extension/TaskInfo.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.windowdecor.extension
+
+import android.app.TaskInfo
+import android.view.WindowInsetsController.APPEARANCE_LIGHT_CAPTION_BARS
+import android.view.WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND
+
+val TaskInfo.isTransparentCaptionBarAppearance: Boolean
+    get() {
+        val appearance = taskDescription?.statusBarAppearance ?: 0
+        return (appearance and APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND) != 0
+    }
+
+val TaskInfo.isLightCaptionBarAppearance: Boolean
+    get() {
+        val appearance = taskDescription?.statusBarAppearance ?: 0
+        return (appearance and APPEARANCE_LIGHT_CAPTION_BARS) != 0
+    }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
index 7e5b9bd..58bbb03 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
@@ -8,12 +8,11 @@
 import android.graphics.Color
 import android.view.View
 import android.view.View.OnLongClickListener
-import android.view.WindowInsetsController.APPEARANCE_LIGHT_CAPTION_BARS
-import android.view.WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND
 import android.widget.ImageButton
 import android.widget.ImageView
 import android.widget.TextView
 import androidx.core.content.withStyledAttributes
+import androidx.core.view.isVisible
 import com.android.internal.R.attr.materialColorOnSecondaryContainer
 import com.android.internal.R.attr.materialColorOnSurface
 import com.android.internal.R.attr.materialColorSecondaryContainer
@@ -22,6 +21,8 @@
 import com.android.internal.R.attr.materialColorSurfaceDim
 import com.android.wm.shell.R
 import com.android.wm.shell.windowdecor.MaximizeButtonView
+import com.android.wm.shell.windowdecor.extension.isLightCaptionBarAppearance
+import com.android.wm.shell.windowdecor.extension.isTransparentCaptionBarAppearance
 
 /**
  * A desktop mode window decoration used when the window is floating (i.e. freeform). It hosts
@@ -76,6 +77,7 @@
         closeWindowButton.imageTintList = ColorStateList.valueOf(color)
         maximizeWindowButton.imageTintList = ColorStateList.valueOf(color)
         expandMenuButton.imageTintList = ColorStateList.valueOf(color)
+        appNameTextView.isVisible = !taskInfo.isTransparentCaptionBarAppearance
         appNameTextView.setTextColor(color)
         appIconImageView.imageAlpha = alpha
         maximizeWindowButton.imageAlpha = alpha
@@ -107,7 +109,7 @@
 
     @ColorInt
     private fun getCaptionBackgroundColor(taskInfo: RunningTaskInfo): Int {
-        if (isTransparentBackgroundRequested(taskInfo)) {
+        if (taskInfo.isTransparentCaptionBarAppearance) {
             return Color.TRANSPARENT
         }
         val materialColorAttr: Int =
@@ -133,10 +135,10 @@
     @ColorInt
     private fun getAppNameAndButtonColor(taskInfo: RunningTaskInfo): Int {
         val materialColorAttr = when {
-            isTransparentBackgroundRequested(taskInfo) &&
-                    isLightCaptionBar(taskInfo) -> materialColorOnSecondaryContainer
-            isTransparentBackgroundRequested(taskInfo) &&
-                    !isLightCaptionBar(taskInfo) -> materialColorOnSurface
+            taskInfo.isTransparentCaptionBarAppearance &&
+                    taskInfo.isLightCaptionBarAppearance -> materialColorOnSecondaryContainer
+            taskInfo.isTransparentCaptionBarAppearance &&
+                    !taskInfo.isLightCaptionBarAppearance -> materialColorOnSurface
             isDarkMode() -> materialColorOnSurface
             else -> materialColorOnSecondaryContainer
         }
@@ -167,16 +169,6 @@
                 Configuration.UI_MODE_NIGHT_YES
     }
 
-    private fun isTransparentBackgroundRequested(taskInfo: RunningTaskInfo): Boolean {
-        val appearance = taskInfo.taskDescription?.statusBarAppearance ?: 0
-        return (appearance and APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND) != 0
-    }
-
-    private fun isLightCaptionBar(taskInfo: RunningTaskInfo): Boolean {
-        val appearance = taskInfo.taskDescription?.statusBarAppearance ?: 0
-        return (appearance and APPEARANCE_LIGHT_CAPTION_BARS) != 0
-    }
-
     companion object {
         private const val TAG = "DesktopModeAppControlsWindowDecorationViewHolder"
         private const val DARK_THEME_UNFOCUSED_OPACITY = 140 // 55%
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
index adf92d8..3380adac 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.appcompat
 
 import android.content.Context
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTestData
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.FlickerTestData
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.server.wm.flicker.helpers.LetterboxAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.wm.shell.flicker.BaseTest
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
index 1e5e42f..f08eba5 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.appcompat
 
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt
index 2fa1ec3..826fc54 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt
@@ -17,13 +17,13 @@
 package com.android.wm.shell.flicker.appcompat
 
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt
index b74aa1d..26e78bf 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt
@@ -18,15 +18,15 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.RequiresDevice
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.datatypes.Rect
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.datatypes.Rect
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt
index 68fa8d2..2aa84b4 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt
@@ -17,13 +17,13 @@
 package com.android.wm.shell.flicker.appcompat
 
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
+import android.tools.Rotation
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
 import androidx.test.filters.RequiresDevice
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
index fcb6931a..443fac1 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.appcompat
 
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
 import androidx.test.filters.RequiresDevice
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt
index 446aad8..7ffa233 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt
@@ -19,17 +19,17 @@
 import android.os.Build
 import android.platform.test.annotations.Postsubmit
 import android.system.helpers.CommandsHelper
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.datatypes.Rect
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.datatypes.Rect
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiDevice
 import androidx.test.uiautomator.Until
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt
index 9792c85..2c0f837 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.appcompat
 
 import android.content.Context
-import android.tools.device.flicker.legacy.FlickerTestData
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.flicker.legacy.FlickerTestData
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiObject2
 import androidx.test.uiautomator.Until
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
index 0c36e29..8eca456 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
@@ -21,12 +21,12 @@
 import android.content.Context
 import android.content.pm.PackageManager
 import android.os.ServiceManager
-import android.tools.common.Rotation
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTestData
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.SYSTEMUI_PACKAGE
+import android.tools.Rotation
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.FlickerTestData
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.SYSTEMUI_PACKAGE
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiObject2
 import androidx.test.uiautomator.Until
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
index 55039f5..bc486c2 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
@@ -18,9 +18,9 @@
 
 import android.os.SystemClock
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.filters.FlakyTest
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiObject2
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
index 9ca7bf1..521c0d0 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
@@ -19,11 +19,11 @@
 import android.content.Context
 import android.graphics.Point
 import android.platform.test.annotations.Presubmit
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.subject.layers.LayersTraceSubject
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import android.util.DisplayMetrics
 import android.view.WindowManager
 import androidx.test.uiautomator.By
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
index b007e6b..e059ac7 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.bubble
 
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import android.view.WindowInsets
 import android.view.WindowManager
 import androidx.test.filters.FlakyTest
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
index 4959672..ef7fbfb 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.bubble
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
 import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
index 0d95574..87224b15 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.bubble
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
 import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index af2db12..d64bfed 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.pip.common.EnterPipTransition
@@ -46,7 +46,7 @@
  * ```
  *     1. All assertions are inherited from [EnterPipTest]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
index 8c0a524..a0edcfb 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -44,7 +44,7 @@
  * ```
  *     1. All assertions are inherited from [AutoEnterPipOnGoToHomeTest]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
index 9256725..031acf4 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.wm.shell.flicker.pip.common.ClosePipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -44,7 +44,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
index 002c019..860307f 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.wm.shell.flicker.pip.common.ClosePipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -44,7 +44,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
index 4cc9547..c554161 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.wm.shell.flicker.pip.common.EnterPipTransition
 import org.junit.Assume
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
index 07cd682..9a1bd26 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
@@ -19,14 +19,14 @@
 import android.app.Activity
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
+import android.tools.Rotation
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.entireScreenCovered
 import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
@@ -60,7 +60,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
@@ -206,6 +206,18 @@
         }
     }
 
+    @Presubmit
+    @Test
+    fun pipLayerRemainInsideVisibleBounds() {
+        // during the transition we assert the center point is within the display bounds, since it
+        // might go outside of bounds as we resize from landscape fullscreen to destination bounds,
+        // and once the animation is over we assert that it's fully within the display bounds, at
+        // which point the device also performs orientation change from landscape to portrait
+        flicker.assertLayersVisibleRegion(pipApp.or(ComponentNameMatcher.PIP_CONTENT_OVERLAY)) {
+            regionsCenterPointInside(startingBounds).then().coversAtMost(endingBounds)
+        }
+    }
+
     /** {@inheritDoc} */
     @FlakyTest(bugId = 267424412)
     @Test
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
index cc94367..f97d8d1 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
@@ -16,9 +16,9 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.wm.shell.flicker.pip.common.EnterPipTransition
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
@@ -41,7 +41,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited from [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
index 7da4429..47bf418 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
@@ -16,9 +16,9 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
@@ -43,7 +43,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
index 0ad9e4c..a356e68 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
@@ -16,9 +16,9 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
@@ -42,7 +42,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited from [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index 89a6c93..25614ef 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -46,7 +46,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
index 8978af0..1964e3c 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
index 2792298..b94989d 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
@@ -17,13 +17,13 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions
@@ -52,7 +52,7 @@
  * ```
  *     1. All assertions are inherited from [EnterPipTest]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
index 4c23153..1ccc7d8 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
@@ -17,13 +17,13 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions
@@ -53,7 +53,7 @@
  * ```
  *     1. All assertions are inherited from [EnterPipTest]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
index 4776206..9b74622 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.pip.common.MovePipShelfHeightTransition
 import com.android.wm.shell.flicker.utils.Direction
@@ -47,7 +47,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
index 425cbfaff..e184cf0 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
@@ -17,14 +17,14 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
+import android.tools.Rotation
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.ImeAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.wm.shell.flicker.pip.common.PipTransition
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
index 18f30d9..490ebd1 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.pip.common.MovePipShelfHeightTransition
 import com.android.wm.shell.flicker.utils.Direction
@@ -47,7 +47,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
index 36047cc..70be58f 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
index c7f2786..a4df69f 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
@@ -18,10 +18,10 @@
 
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.server.wm.flicker.testapp.ActivityOptions
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
index cabc1cc..90b9798 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.pip
 
 import android.graphics.Rect
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.rules.RemoveAllTasksButHomeRule
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.setRotation
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
index 381f947..6841706 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.subject.exceptions.IncorrectRegionException
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.subject.exceptions.IncorrectRegionException
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
index 1f69847..9a6dacb 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
@@ -19,13 +19,13 @@
 import android.app.Activity
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
+import android.tools.Rotation
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
index 308ece4..d2f803e 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.wm.shell.flicker.pip.common.PipTransition
@@ -50,7 +50,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited from [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt
index be77171..c9f4a6c 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt
@@ -17,13 +17,13 @@
 package com.android.wm.shell.flicker.pip.apps
 
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.Rotation
+import android.tools.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.flicker.junit.FlickerBuilderProvider
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerBuilderProvider
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.wm.shell.flicker.pip.common.EnterPipTransition
 import org.junit.Test
 import org.junit.runners.Parameterized
@@ -101,8 +101,9 @@
     override fun pipLayerReduces() {
         flicker.assertLayers {
             val pipLayerList =
-                this.layers { standardAppHelper.packageNameMatcher.layerMatchesAnyOf(it)
-                        && it.isVisible }
+                this.layers {
+                    standardAppHelper.packageNameMatcher.layerMatchesAnyOf(it) && it.isVisible
+                }
             pipLayerList.zipWithNext { previous, current ->
                 current.visibleRegion.notBiggerThan(previous.visibleRegion.region)
             }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt
index 4c2eff3..8865010 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt
@@ -26,9 +26,9 @@
 import android.os.SystemClock
 import android.platform.test.annotations.Postsubmit
 import android.tools.device.apphelpers.MapsAppHelper
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.filters.RequiresDevice
 import org.junit.Assume
 import org.junit.FixMethodOrder
@@ -53,7 +53,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited from [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt
index 143f7a7..9b51538 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt
@@ -18,14 +18,14 @@
 
 import android.Manifest
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.NetflixAppHelper
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.statusBarLayerPositionAtEnd
 import org.junit.Assume
@@ -51,7 +51,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited from [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt
index 509b32c..3ae5937 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt
@@ -18,11 +18,11 @@
 
 import android.Manifest
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.YouTubeAppHelper
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.filters.RequiresDevice
 import org.junit.Assume
 import org.junit.FixMethodOrder
@@ -47,7 +47,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited from [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt
index 751f2bc..dc12259 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.pip.common
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher.Companion.LAUNCHER
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.traces.component.ComponentNameMatcher.Companion.LAUNCHER
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.server.wm.flicker.helpers.setRotation
 import org.junit.Test
 import org.junit.runners.Parameterized
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt
index 9c129e4..3d9eae6 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.pip.common
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import org.junit.Test
 import org.junit.runners.Parameterized
 
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt
index 9450bdd..7b6839d 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.pip.common
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import org.junit.Test
 import org.junit.runners.Parameterized
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt
index 7e42bc1..f4baf5f 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.pip.common
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.subject.region.RegionSubject
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.subject.region.RegionSubject
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
 import com.android.wm.shell.flicker.utils.Direction
 import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
index 7b7f1d7..fd467e3 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
@@ -19,12 +19,12 @@
 import android.app.Instrumentation
 import android.content.Intent
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
-import android.tools.device.helpers.WindowUtils
+import android.tools.Rotation
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
+import android.tools.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt
index c6cbcd0..4e1a8ff 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt
@@ -17,7 +17,7 @@
 package com.android.wm.shell.flicker.pip.tv
 
 import android.app.Instrumentation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.BySelector
 import androidx.test.uiautomator.UiObject2
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
index 0d18535..2854222 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
@@ -20,8 +20,8 @@
 import android.app.IActivityManager
 import android.app.IProcessObserver
 import android.os.SystemClock
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.parsers.WindowManagerStateHelper
 import android.view.Surface.ROTATION_0
 import android.view.Surface.rotationToString
 import com.android.wm.shell.flicker.utils.SYSTEM_UI_PACKAGE_NAME
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/common/Utils.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/common/Utils.kt
index 4bd7954..4c6c6cc 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/common/Utils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/common/Utils.kt
@@ -20,13 +20,13 @@
 import android.platform.test.rule.NavigationModeRule
 import android.platform.test.rule.PressHomeRule
 import android.platform.test.rule.UnlockScreenRule
-import android.tools.common.NavBar
-import android.tools.common.Rotation
+import android.tools.NavBar
+import android.tools.Rotation
 import android.tools.device.apphelpers.MessagingAppHelper
-import android.tools.device.flicker.rules.ArtifactSaverRule
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
-import android.tools.device.flicker.rules.LaunchAppRule
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
+import android.tools.flicker.rules.ArtifactSaverRule
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.flicker.rules.LaunchAppRule
+import android.tools.flicker.rules.RemoveAllTasksButHomeRule
 import androidx.test.platform.app.InstrumentationRegistry
 import org.junit.rules.RuleChain
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt
index a5c5122..1684a26 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt
index 092fb67..3b5fad6 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt
index 69499b9..2b8a903 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt
index bd627f4..b284fe1 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
index a8f4d0a..a400ee4 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
index cee9bbf..7f5ee4c 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt
index c1b3aad..1b075c4 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt
index c6e2e85..6ca3737 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
index 169b5cf..f7d231f0 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
index 412c011..ab819fa 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
index 6e4cf9f..a6b732c 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
index cc28702..07e5f4b 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
index 736604f..2725694 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
index 8df8dfa..58cc4d7 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
index 378f055..85897a1 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
index b33d262..891b6df 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
index b1d3858..7983652 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
index 6d824c7..1bdea66 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
index f1d3d0c..bab0c0a 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
index a867bac..17a59ab 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
index 76247ba..2c36d64 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
index e179da8..6e91d04 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
index 20f554f..a921b46 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
index f7776ee..05f8912 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
index 4ff0b4362..1ae1f53 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
index 930f31d..e14ca55 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt
index 3da61e5..ce0c4c4 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt
index 627ae18..5a8d2d5 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
index c744103..d442615 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
@@ -16,12 +16,12 @@
 
 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 android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.UnlockKeyguardToSplitScreen
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
index 11a4e02..ddc8a06 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
@@ -16,12 +16,12 @@
 
 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 android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.UnlockKeyguardToSplitScreen
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt
index e37d806..64293b2 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt
index 2a50912..517ba2d 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt
index d5da1a8..1bafe3b 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt
index 7fdcb9b..fd0100f 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
index 308e954..850b3d8 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
index 39e75bd..0b752bf 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt
index e18da17..3c52aa7 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt
index 00d60e7..c2e21b8 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
index d7efbc8..bf85ab4 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
index 4eece3f..0ac4ca2 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
index d96b056..80bd088 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
index 809b690..0dffb4a 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
index bbdf2d7..b721f2f 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
index 5c29fd8..22cbc77 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
index a7398eb..ac0f9e2 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
index eae88ad..f7a229d 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
index 7e8ee04..6dbbcb0 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
index 9295c33..bd69ea9 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
index 4b59e9f..404b96f 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
index 5ff36d4..a79687d 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
index c0cb721..b52eb4c 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
index 8c14088..d79620c 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
index 7b6614b..d27bfa1 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
index 5df5be9..3c7d4d4 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
index 9d63003..26a2034 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
index 9fa04b2..5154b35 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt
index 9386aa2..86451c5 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt
index 5ef2167..baf72b4 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt
index 824e454..89ef91e 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt
index 4c39104..c1a8ee7 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt
index f6d1afc..600855a 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
index db5a32a..c671fbe 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
index 03170a3..a189325 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt
index c52ada3b..4336692 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
index 479d01d..8c7e63f 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
index 625c56b..2072831 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt
index f1a011c..09e77cc 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt
index c9b1c91..babdae1 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt
@@ -18,11 +18,11 @@
 
 import android.app.Instrumentation
 import android.graphics.Point
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.helpers.WindowUtils
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.helpers.WindowUtils
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt
index 72f2db3..3e85479 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt
index 511de4f..655ae4e 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt
index 558d2bf..2208258 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt
index ecd68295..2ac63c2 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt
index f50d5c7..35b122d 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
index 6b97169..d74c59e 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.component.EdgeExtensionComponentMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.component.EdgeExtensionComponentMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.CopyContentInSplitBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
index 51588569..dd45f65 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
@@ -18,10 +18,10 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.helpers.WindowUtils
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.helpers.WindowUtils
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.DismissSplitScreenByDividerBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
index fc6c2b3..6d396ea 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.DismissSplitScreenByGoHomeBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
index 8b1689a..2ed916e 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.DragDividerToResizeBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
index 99613f3..1a455311 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
@@ -18,11 +18,11 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromAllAppsBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
index 756a7fa..0cb1e40 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
@@ -18,11 +18,11 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromNotificationBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
index 121b46a..ff406b7 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromShortcutBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
index 99deb92..2b81798 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
@@ -18,11 +18,11 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromTaskbarBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
index 212a4e3..186af54 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenFromOverviewBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
index fac97c8..9dde490 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
@@ -18,11 +18,11 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchAppByDoubleTapDividerBenchmark
 import com.android.wm.shell.flicker.utils.ICommonAssertions
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
index 284c32e..5222b08 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromAnotherAppBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
index 9e6448f..a8a8ae8 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromHomeBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
index 8e28712..836f664 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromRecentBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
index fb0193b..3c4a1ca 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBetweenSplitPairsBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt
index 715a533..8724346 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.wm.shell.flicker.splitscreen.benchmark.SplitScreenBase
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
index e6a2022..16d7331 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
@@ -18,14 +18,14 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.common.flicker.subject.region.RegionSubject
-import android.tools.common.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.subject.layers.LayersTraceSubject
+import android.tools.flicker.subject.region.RegionSubject
+import android.tools.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.UnlockKeyguardToSplitScreenBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
index df1c9a2..9c5a3fe 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
index d01eab0..c99fcc4 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
@@ -16,10 +16,10 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
index e36bd33..ef3a879 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
@@ -16,10 +16,10 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
index 050d389..18550d7 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
@@ -16,10 +16,10 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.Assume
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
index 5c43cbd..d16c5d7 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
index cd3fbab..f8be6be 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.Assume
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
index 15ad0c1..a99ef64 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
index ca8adb1..f584009 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
index 5e5e7d7..7084f6a 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
@@ -16,10 +16,10 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt
index a0e437c..4b10603 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt
@@ -17,8 +17,8 @@
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
 import android.content.Context
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.wm.shell.flicker.BaseBenchmarkTest
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
index e39c3c9..38206c3 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
@@ -16,14 +16,14 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
index 32284ba..3a2316f 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
index a926ec9..ded0b07 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
index d2e1d52..7b1397b 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
index 9d6b251..457288f 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
@@ -16,10 +16,10 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt
index e71834d..7493538 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt
index e9363f7..d03c2f1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker
 
 import android.app.Instrumentation
-import android.tools.device.flicker.junit.FlickerBuilderProvider
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerBuilderProvider
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
index 568650d..a19d232 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
@@ -17,8 +17,8 @@
 package com.android.wm.shell.flicker
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.wm.shell.flicker.utils.ICommonAssertions
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt
index f1cb37e..3df0954 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt
@@ -18,13 +18,13 @@
 
 package com.android.wm.shell.flicker.utils
 
-import android.tools.common.Rotation
-import android.tools.common.datatypes.Region
-import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.common.traces.component.IComponentMatcher
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.helpers.WindowUtils
+import android.tools.Rotation
+import android.tools.datatypes.Region
+import android.tools.flicker.subject.layers.LayerTraceEntrySubject
+import android.tools.flicker.subject.layers.LayersTraceSubject
+import android.tools.traces.component.IComponentMatcher
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.helpers.WindowUtils
 
 fun LegacyFlickerTest.appPairsDividerIsVisibleAtEnd() {
     assertLayersEnd { this.isVisible(APP_PAIR_SPLIT_DIVIDER_COMPONENT) }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonConstants.kt
index 3b66d6a..fb21fcc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonConstants.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonConstants.kt
@@ -18,7 +18,7 @@
 
 package com.android.wm.shell.flicker.utils
 
-import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.traces.component.ComponentNameMatcher
 
 const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui"
 const val LAUNCHER_UI_PACKAGE_NAME = "com.google.android.apps.nexuslauncher"
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt
index 7f58ced..50c0435 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt
@@ -17,8 +17,8 @@
 package com.android.wm.shell.flicker.utils
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.server.wm.flicker.entireScreenCovered
 import com.android.server.wm.flicker.navBarLayerIsVisibleAtStartAndEnd
 import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt
index 3244ebc..4e9a9d6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt
@@ -19,14 +19,14 @@
 import android.app.Instrumentation
 import android.graphics.Point
 import android.os.SystemClock
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.component.IComponentMatcher
-import android.tools.common.traces.component.IComponentNameMatcher
+import android.tools.Rotation
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.component.IComponentMatcher
+import android.tools.traces.component.IComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import android.view.InputDevice
 import android.view.MotionEvent
 import android.view.ViewConfiguration
diff --git a/libs/WindowManager/Shell/tests/unittest/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp
index 8c47116..32c0703 100644
--- a/libs/WindowManager/Shell/tests/unittest/Android.bp
+++ b/libs/WindowManager/Shell/tests/unittest/Android.bp
@@ -24,7 +24,10 @@
 
 android_test {
     name: "WMShellUnitTests",
-
+    defaults: [
+        // For ExtendedMockito dependencies.
+        "modules-utils-testable-device-config-defaults",
+    ],
     srcs: [
         "**/*.java",
         "**/*.kt",
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
index 01e2f98..2c0aa12 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
@@ -38,6 +38,7 @@
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.SurfaceControl;
+import android.view.inputmethod.ImeTracker;
 
 import androidx.test.filters.SmallTest;
 
@@ -51,6 +52,12 @@
 
 import java.util.concurrent.Executor;
 
+/**
+ * Tests for the display IME controller.
+ *
+ * <p> Build/Install/Run:
+ *  atest WMShellUnitTests:DisplayImeControllerTest
+ */
 @SmallTest
 public class DisplayImeControllerTest extends ShellTestCase {
 
@@ -99,13 +106,13 @@
 
     @Test
     public void showInsets_schedulesNoWorkOnExecutor() {
-        mPerDisplay.showInsets(ime(), true /* fromIme */, null /* statsToken */);
+        mPerDisplay.showInsets(ime(), true /* fromIme */, ImeTracker.Token.empty());
         verifyZeroInteractions(mExecutor);
     }
 
     @Test
     public void hideInsets_schedulesNoWorkOnExecutor() {
-        mPerDisplay.hideInsets(ime(), true /* fromIme */, null /* statsToken */);
+        mPerDisplay.hideInsets(ime(), true /* fromIme */, ImeTracker.Token.empty());
         verifyZeroInteractions(mExecutor);
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java
index 956f1cd..669e433 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java
@@ -50,6 +50,12 @@
 
 import java.util.List;
 
+/**
+ * Tests for the display insets controller.
+ *
+ * <p> Build/Install/Run:
+ *  atest WMShellUnitTests:DisplayInsetsControllerTest
+ */
 @SmallTest
 public class DisplayInsetsControllerTest extends ShellTestCase {
 
@@ -114,9 +120,9 @@
         mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).insetsChanged(null);
         mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).insetsControlChanged(null, null);
         mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).showInsets(0, false,
-                null /* statsToken */);
+                ImeTracker.Token.empty());
         mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).hideInsets(0, false,
-                null /* statsToken */);
+                ImeTracker.Token.empty());
         mExecutor.flushAll();
 
         assertTrue(defaultListener.topFocusedWindowChangedCount == 1);
@@ -136,9 +142,9 @@
         mInsetsControllersByDisplayId.get(SECOND_DISPLAY).insetsChanged(null);
         mInsetsControllersByDisplayId.get(SECOND_DISPLAY).insetsControlChanged(null, null);
         mInsetsControllersByDisplayId.get(SECOND_DISPLAY).showInsets(0, false,
-                null /* statsToken */);
+                ImeTracker.Token.empty());
         mInsetsControllersByDisplayId.get(SECOND_DISPLAY).hideInsets(0, false,
-                null /* statsToken */);
+                ImeTracker.Token.empty());
         mExecutor.flushAll();
 
         assertTrue(defaultListener.topFocusedWindowChangedCount == 1);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt
new file mode 100644
index 0000000..4548fcb
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.internal.util.FrameworkStatsLog
+import com.android.modules.utils.testing.ExtendedMockitoRule
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.mockito.kotlin.eq
+
+/**
+ * Tests for [DesktopModeEventLogger].
+ */
+class DesktopModeEventLoggerTest {
+
+    private val desktopModeEventLogger  = DesktopModeEventLogger()
+
+    @JvmField
+    @Rule
+    val extendedMockitoRule = ExtendedMockitoRule.Builder(this)
+            .mockStatic(FrameworkStatsLog::class.java).build()!!
+
+    @Test
+    fun logSessionEnter_enterReason() = runBlocking {
+        desktopModeEventLogger.logSessionEnter(sessionId = SESSION_ID, EnterReason.UNKNOWN_ENTER)
+
+        ExtendedMockito.verify {
+            FrameworkStatsLog.write(
+                eq(FrameworkStatsLog.DESKTOP_MODE_UI_CHANGED),
+                /* event */
+                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__ENTER),
+                /* enter_reason */
+                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__UNKNOWN_ENTER),
+                /* exit_reason */
+                eq(0),
+                /* sessionId */
+                eq(SESSION_ID)
+            )
+        }
+    }
+
+    @Test
+    fun logSessionExit_exitReason() = runBlocking {
+        desktopModeEventLogger.logSessionExit(sessionId = SESSION_ID, ExitReason.UNKNOWN_EXIT)
+
+        ExtendedMockito.verify {
+            FrameworkStatsLog.write(
+                eq(FrameworkStatsLog.DESKTOP_MODE_UI_CHANGED),
+                /* event */
+                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__EXIT),
+                /* enter_reason */
+                eq(0),
+                /* exit_reason */
+                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__UNKNOWN_EXIT),
+                /* sessionId */
+                eq(SESSION_ID)
+            )
+        }
+    }
+
+    @Test
+    fun logTaskAdded_taskUpdate() = runBlocking {
+        desktopModeEventLogger.logTaskAdded(sessionId = SESSION_ID, TASK_UPDATE)
+
+        ExtendedMockito.verify {
+            FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
+                /* task_event */
+                eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_ADDED),
+                /* instance_id */
+                eq(TASK_UPDATE.instanceId),
+                /* uid */
+                eq(TASK_UPDATE.uid),
+                /* task_height */
+                eq(TASK_UPDATE.taskHeight),
+                /* task_width */
+                eq(TASK_UPDATE.taskWidth),
+                /* task_x */
+                eq(TASK_UPDATE.taskX),
+                /* task_y */
+                eq(TASK_UPDATE.taskY),
+                /* session_id */
+                eq(SESSION_ID))
+        }
+    }
+
+    @Test
+    fun logTaskRemoved_taskUpdate() = runBlocking {
+        desktopModeEventLogger.logTaskRemoved(sessionId = SESSION_ID, TASK_UPDATE)
+
+        ExtendedMockito.verify {
+            FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
+                /* task_event */
+                eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_REMOVED),
+                /* instance_id */
+                eq(TASK_UPDATE.instanceId),
+                /* uid */
+                eq(TASK_UPDATE.uid),
+                /* task_height */
+                eq(TASK_UPDATE.taskHeight),
+                /* task_width */
+                eq(TASK_UPDATE.taskWidth),
+                /* task_x */
+                eq(TASK_UPDATE.taskX),
+                /* task_y */
+                eq(TASK_UPDATE.taskY),
+                /* session_id */
+                eq(SESSION_ID))
+        }
+    }
+
+    @Test
+    fun logTaskInfoChanged_taskUpdate() = runBlocking {
+        desktopModeEventLogger.logTaskInfoChanged(sessionId = SESSION_ID, TASK_UPDATE)
+
+        ExtendedMockito.verify {
+            FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
+                /* task_event */
+                eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED),
+                /* instance_id */
+                eq(TASK_UPDATE.instanceId),
+                /* uid */
+                eq(TASK_UPDATE.uid),
+                /* task_height */
+                eq(TASK_UPDATE.taskHeight),
+                /* task_width */
+                eq(TASK_UPDATE.taskWidth),
+                /* task_x */
+                eq(TASK_UPDATE.taskX),
+                /* task_y */
+                eq(TASK_UPDATE.taskY),
+                /* session_id */
+                eq(SESSION_ID))
+        }
+    }
+
+    companion object {
+        private const val SESSION_ID = 1
+        private const val TASK_ID = 1
+        private const val TASK_UID = 1
+        private const val TASK_X = 0
+        private const val TASK_Y = 0
+        private const val TASK_HEIGHT = 100
+        private const val TASK_WIDTH = 100
+
+        private val TASK_UPDATE = TaskUpdate(
+            TASK_ID, TASK_UID, TASK_HEIGHT, TASK_WIDTH, TASK_X, TASK_Y
+        )
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt
index f8ce4ee..9703dce 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt
@@ -56,18 +56,16 @@
             context, taskSurface, taskDisplayAreaOrganizer)
         whenever(displayLayout.width()).thenReturn(DISPLAY_BOUNDS.width())
         whenever(displayLayout.height()).thenReturn(DISPLAY_BOUNDS.height())
+        whenever(displayLayout.stableInsets()).thenReturn(STABLE_INSETS)
     }
 
     @Test
     fun testFullscreenRegionCalculation() {
         val transitionHeight = context.resources.getDimensionPixelSize(
-            R.dimen.desktop_mode_transition_area_height)
+            R.dimen.desktop_mode_fullscreen_from_desktop_height)
         val fromFreeformWidth = mContext.resources.getDimensionPixelSize(
             R.dimen.desktop_mode_fullscreen_from_desktop_width
         )
-        val fromFreeformHeight = mContext.resources.getDimensionPixelSize(
-            R.dimen.desktop_mode_fullscreen_from_desktop_height
-        )
         var testRegion = visualIndicator.calculateFullscreenRegion(displayLayout,
             WINDOWING_MODE_FULLSCREEN, CAPTION_HEIGHT)
         assertThat(testRegion.bounds).isEqualTo(Rect(0, -50, 2400, transitionHeight))
@@ -77,7 +75,7 @@
             DISPLAY_BOUNDS.width() / 2 - fromFreeformWidth / 2,
             -50,
             DISPLAY_BOUNDS.width() / 2 + fromFreeformWidth / 2,
-            fromFreeformHeight))
+            2 * STABLE_INSETS.top))
         testRegion = visualIndicator.calculateFullscreenRegion(displayLayout,
             WINDOWING_MODE_MULTI_WINDOW, CAPTION_HEIGHT)
         assertThat(testRegion.bounds).isEqualTo(Rect(0, -50, 2400, transitionHeight))
@@ -135,5 +133,12 @@
         private const val TRANSITION_AREA_WIDTH = 32
         private const val CAPTION_HEIGHT = 50
         private val DISPLAY_BOUNDS = Rect(0, 0, 2400, 1600)
+        private const val NAVBAR_HEIGHT = 50
+        private val STABLE_INSETS = Rect(
+            DISPLAY_BOUNDS.left,
+            DISPLAY_BOUNDS.top + CAPTION_HEIGHT,
+            DISPLAY_BOUNDS.right,
+            DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT
+        )
     }
 }
\ No newline at end of file
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 383621b..35c803b 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
@@ -781,6 +781,23 @@
         )
     }
 
+    @Test
+    fun moveFocusedTaskToFullscreen() {
+        val task1 = setUpFreeformTask()
+        val task2 = setUpFreeformTask()
+        val task3 = setUpFreeformTask()
+
+        task1.isFocused = false
+        task2.isFocused = true
+        task3.isFocused = false
+
+        controller.enterFullscreen(DEFAULT_DISPLAY)
+
+        val wct = getLatestExitDesktopWct()
+        assertThat(wct.changes[task2.token.asBinder()]?.windowingMode)
+                .isEqualTo(WINDOWING_MODE_FULLSCREEN)
+    }
+
     private fun setUpFreeformTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
         val task = createFreeformTask(displayId)
         whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index 1b347e0..5dd9d8a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -22,9 +22,11 @@
 import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
 import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
 import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
+import static android.content.ClipDescription.MIMETYPE_TEXT_INTENT;
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
@@ -46,6 +48,8 @@
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.quality.Strictness.LENIENT;
 
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
@@ -61,6 +65,7 @@
 import android.graphics.Insets;
 import android.os.RemoteException;
 import android.view.DisplayInfo;
+import android.view.DragEvent;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
@@ -70,12 +75,15 @@
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.draganddrop.DragAndDropPolicy.Target;
 import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.startingsurface.TaskSnapshotWindow;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -107,6 +115,7 @@
     private DragAndDropPolicy mPolicy;
 
     private ClipData mActivityClipData;
+    private ClipData mLaunchableIntentClipData;
     private ClipData mNonResizeableActivityClipData;
     private ClipData mTaskClipData;
     private ClipData mShortcutClipData;
@@ -115,9 +124,16 @@
     private ActivityManager.RunningTaskInfo mFullscreenAppTask;
     private ActivityManager.RunningTaskInfo mNonResizeableFullscreenAppTask;
 
+    private MockitoSession mMockitoSession;
+
     @Before
     public void setUp() throws RemoteException {
         MockitoAnnotations.initMocks(this);
+        mMockitoSession = mockitoSession()
+                .strictness(LENIENT)
+                .mockStatic(DragUtils.class)
+                .startMocking();
+        when(DragUtils.canHandleDrag(any())).thenReturn(true);
 
         Resources res = mock(Resources.class);
         Configuration config = new Configuration();
@@ -134,11 +150,12 @@
         mInsets = Insets.of(0, 0, 0, 0);
 
         mPolicy = spy(new DragAndDropPolicy(mContext, mSplitScreenStarter, mSplitScreenStarter));
-        mActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
-        mNonResizeableActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
+        mActivityClipData = createAppClipData(MIMETYPE_APPLICATION_ACTIVITY);
+        mLaunchableIntentClipData = createIntentClipData();
+        mNonResizeableActivityClipData = createAppClipData(MIMETYPE_APPLICATION_ACTIVITY);
         setClipDataResizeable(mNonResizeableActivityClipData, false);
-        mTaskClipData = createClipData(MIMETYPE_APPLICATION_TASK);
-        mShortcutClipData = createClipData(MIMETYPE_APPLICATION_SHORTCUT);
+        mTaskClipData = createAppClipData(MIMETYPE_APPLICATION_TASK);
+        mShortcutClipData = createAppClipData(MIMETYPE_APPLICATION_SHORTCUT);
 
         mHomeTask = createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
         mFullscreenAppTask = createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
@@ -149,10 +166,15 @@
         setRunningTask(mFullscreenAppTask);
     }
 
+    @After
+    public void tearDown() {
+        mMockitoSession.finishMocking();
+    }
+
     /**
-     * Creates a clip data that is by default resizeable.
+     * Creates an app-based clip data that is by default resizeable.
      */
-    private ClipData createClipData(String mimeType) {
+    private ClipData createAppClipData(String mimeType) {
         ClipDescription clipDescription = new ClipDescription(mimeType, new String[] { mimeType });
         Intent i = new Intent();
         switch (mimeType) {
@@ -164,7 +186,9 @@
                 i.putExtra(Intent.EXTRA_TASK_ID, 12345);
                 break;
             case MIMETYPE_APPLICATION_ACTIVITY:
-                i.putExtra(ClipDescription.EXTRA_PENDING_INTENT, mock(PendingIntent.class));
+                final PendingIntent pi = mock(PendingIntent.class);
+                doReturn(android.os.Process.myUserHandle()).when(pi).getCreatorUserHandle();
+                i.putExtra(ClipDescription.EXTRA_PENDING_INTENT, pi);
                 break;
         }
         i.putExtra(Intent.EXTRA_USER, android.os.Process.myUserHandle());
@@ -175,6 +199,22 @@
         return data;
     }
 
+    /**
+     * Creates an intent-based clip data that is by default resizeable.
+     */
+    private ClipData createIntentClipData() {
+        ClipDescription clipDescription = new ClipDescription("Intent",
+                new String[] { MIMETYPE_TEXT_INTENT });
+        PendingIntent intent = mock(PendingIntent.class);
+        when(intent.getCreatorUserHandle()).thenReturn(android.os.Process.myUserHandle());
+        ClipData.Item item = new ClipData.Item.Builder()
+                .setIntentSender(intent.getIntentSender())
+                .build();
+        ClipData data = new ClipData(clipDescription, item);
+        when(DragUtils.getLaunchIntent((ClipData) any())).thenReturn(intent);
+        return data;
+    }
+
     private ActivityManager.RunningTaskInfo createTaskInfo(int winMode, int actType) {
         ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
         info.configuration.windowConfiguration.setActivityType(actType);
@@ -204,58 +244,85 @@
 
     @Test
     public void testDragAppOverFullscreenHome_expectOnlyFullscreenTarget() {
+        dragOverFullscreenHome_expectOnlyFullscreenTarget(mActivityClipData);
+    }
+
+    @Test
+    public void testDragAppOverFullscreenApp_expectSplitScreenTargets() {
+        dragOverFullscreenApp_expectSplitScreenTargets(mActivityClipData);
+    }
+
+    @Test
+    public void testDragAppOverFullscreenAppPhone_expectVerticalSplitScreenTargets() {
+        dragOverFullscreenAppPhone_expectVerticalSplitScreenTargets(mActivityClipData);
+    }
+
+    @Test
+    public void testDragIntentOverFullscreenHome_expectOnlyFullscreenTarget() {
+        dragOverFullscreenHome_expectOnlyFullscreenTarget(mLaunchableIntentClipData);
+    }
+
+    @Test
+    public void testDragIntentOverFullscreenApp_expectSplitScreenTargets() {
+        dragOverFullscreenApp_expectSplitScreenTargets(mLaunchableIntentClipData);
+    }
+
+    @Test
+    public void testDragIntentOverFullscreenAppPhone_expectVerticalSplitScreenTargets() {
+        dragOverFullscreenAppPhone_expectVerticalSplitScreenTargets(mLaunchableIntentClipData);
+    }
+
+    private void dragOverFullscreenHome_expectOnlyFullscreenTarget(ClipData data) {
         doReturn(true).when(mSplitScreenStarter).isLeftRightSplit();
         setRunningTask(mHomeTask);
-        DragSession dragSession = new DragSession(mContext, mActivityTaskManager,
-                mLandscapeDisplayLayout, mActivityClipData);
+        DragSession dragSession = new DragSession(mActivityTaskManager,
+                mLandscapeDisplayLayout, data);
         dragSession.update();
         mPolicy.start(dragSession, mLoggerSessionId);
         ArrayList<Target> targets = assertExactTargetTypes(
                 mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
 
-        mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+        mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN));
         verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
                 eq(SPLIT_POSITION_UNDEFINED), any());
     }
 
-    @Test
-    public void testDragAppOverFullscreenApp_expectSplitScreenTargets() {
+    private void dragOverFullscreenApp_expectSplitScreenTargets(ClipData data) {
         doReturn(true).when(mSplitScreenStarter).isLeftRightSplit();
         setRunningTask(mFullscreenAppTask);
-        DragSession dragSession = new DragSession(mContext, mActivityTaskManager,
-                mLandscapeDisplayLayout, mActivityClipData);
+        DragSession dragSession = new DragSession(mActivityTaskManager,
+                mLandscapeDisplayLayout, data);
         dragSession.update();
         mPolicy.start(dragSession, mLoggerSessionId);
         ArrayList<Target> targets = assertExactTargetTypes(
                 mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
 
-        mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_LEFT), mActivityClipData);
+        mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_LEFT));
         verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
                 eq(SPLIT_POSITION_TOP_OR_LEFT), any());
         reset(mSplitScreenStarter);
 
-        mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
+        mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT));
         verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
                 eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
     }
 
-    @Test
-    public void testDragAppOverFullscreenAppPhone_expectVerticalSplitScreenTargets() {
+    private void dragOverFullscreenAppPhone_expectVerticalSplitScreenTargets(ClipData data) {
         doReturn(false).when(mSplitScreenStarter).isLeftRightSplit();
         setRunningTask(mFullscreenAppTask);
-        DragSession dragSession = new DragSession(mContext, mActivityTaskManager,
-                mPortraitDisplayLayout, mActivityClipData);
+        DragSession dragSession = new DragSession(mActivityTaskManager,
+                mPortraitDisplayLayout, data);
         dragSession.update();
         mPolicy.start(dragSession, mLoggerSessionId);
         ArrayList<Target> targets = assertExactTargetTypes(
                 mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
 
-        mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_TOP), mActivityClipData);
+        mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_TOP));
         verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
                 eq(SPLIT_POSITION_TOP_OR_LEFT), any());
         reset(mSplitScreenStarter);
 
-        mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
+        mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM));
         verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
                 eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
     }
@@ -263,7 +330,7 @@
     @Test
     public void testTargetHitRects() {
         setRunningTask(mFullscreenAppTask);
-        DragSession dragSession = new DragSession(mContext, mActivityTaskManager,
+        DragSession dragSession = new DragSession(mActivityTaskManager,
                 mLandscapeDisplayLayout, mActivityClipData);
         dragSession.update();
         mPolicy.start(dragSession, mLoggerSessionId);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index d4e9ac9..e74c804 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -36,7 +36,6 @@
 import android.content.pm.ActivityInfo;
 import android.graphics.Rect;
 import android.os.RemoteException;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.Rational;
@@ -45,6 +44,8 @@
 import android.view.SurfaceControl;
 import android.window.WindowContainerToken;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.wm.shell.MockSurfaceControlHelper;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.ShellTestCase;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 5d968d3..3384509 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -42,10 +42,11 @@
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.RemoteException;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.common.DisplayController;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java
index 45f6c8c..72db6e0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java
@@ -23,20 +23,21 @@
 import static com.android.wm.shell.pip.tv.TvPipAction.ACTION_FULLSCREEN;
 import static com.android.wm.shell.pip.tv.TvPipAction.ACTION_MOVE;
 
-import static java.util.Collections.EMPTY_LIST;
-
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import static java.util.Collections.EMPTY_LIST;
+
 import android.app.PendingIntent;
 import android.app.RemoteAction;
 import android.graphics.drawable.Icon;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.common.pip.PipMediaController;
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
index 0504439..fbc0db9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
@@ -32,7 +32,6 @@
 import android.app.ActivityManager;
 import android.graphics.Rect;
 import android.os.IBinder;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.SurfaceControl;
@@ -40,6 +39,8 @@
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.transition.Transitions;
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index f84685a..9bb5482 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -29,8 +29,10 @@
 import android.os.Handler
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import android.util.SparseArray
 import android.view.Choreographer
 import android.view.Display.DEFAULT_DISPLAY
+import android.view.IWindowManager
 import android.view.InputChannel
 import android.view.InputMonitor
 import android.view.InsetsSource
@@ -71,6 +73,8 @@
 import org.mockito.kotlin.whenever
 import java.util.Optional
 import java.util.function.Supplier
+import org.mockito.Mockito
+import org.mockito.kotlin.spy
 
 
 /** Tests of [DesktopModeWindowDecorViewModel]  */
@@ -96,10 +100,12 @@
     @Mock private lateinit var mockShellExecutor: ShellExecutor
     @Mock private lateinit var mockRootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
     @Mock private lateinit var mockShellCommandHandler: ShellCommandHandler
+    @Mock private lateinit var mockWindowManager: IWindowManager
 
     private val transactionFactory = Supplier<SurfaceControl.Transaction> {
         SurfaceControl.Transaction()
     }
+    private val windowDecorByTaskIdSpy = spy(SparseArray<DesktopModeWindowDecoration>())
 
     private lateinit var shellInit: ShellInit
     private lateinit var desktopModeOnInsetsChangedListener: DesktopModeOnInsetsChangedListener
@@ -108,12 +114,15 @@
     @Before
     fun setUp() {
         shellInit = ShellInit(mockShellExecutor)
+        windowDecorByTaskIdSpy.clear()
         desktopModeWindowDecorViewModel = DesktopModeWindowDecorViewModel(
                 mContext,
+                mockShellExecutor,
                 mockMainHandler,
                 mockMainChoreographer,
                 shellInit,
                 mockShellCommandHandler,
+                mockWindowManager,
                 mockTaskOrganizer,
                 mockDisplayController,
                 mockShellController,
@@ -124,7 +133,8 @@
                 mockDesktopModeWindowDecorFactory,
                 mockInputMonitorFactory,
                 transactionFactory,
-                mockRootTaskDisplayAreaOrganizer
+                mockRootTaskDisplayAreaOrganizer,
+            windowDecorByTaskIdSpy
         )
 
         whenever(mockDisplayController.getDisplayLayout(any())).thenReturn(mockDisplayLayout)
@@ -328,6 +338,19 @@
         verify(decoration, times(1)).relayout(task)
     }
 
+    @Test
+    fun testDestroyWindowDecoration_closesBeforeCleanup() {
+        val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM)
+        val decoration = setUpMockDecorationForTask(task)
+        val inOrder = Mockito.inOrder(decoration, windowDecorByTaskIdSpy)
+
+        onTaskOpening(task)
+        desktopModeWindowDecorViewModel.destroyWindowDecoration(task)
+
+        inOrder.verify(decoration).close()
+        inOrder.verify(windowDecorByTaskIdSpy).remove(task.taskId)
+    }
+
     private fun onTaskOpening(task: RunningTaskInfo, leash: SurfaceControl = SurfaceControl()) {
         desktopModeWindowDecorViewModel.onTaskOpening(
                 task,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index 40e61dd..9e62bd2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -16,6 +16,10 @@
 
 package com.android.wm.shell.windowdecor;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.any;
@@ -168,6 +172,57 @@
         assertThat(relayoutParams.mCornerRadius).isGreaterThan(0);
     }
 
+    @Test
+    public void updateRelayoutParams_freeformAndTransparent_allowsInputFallthrough() {
+        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        taskInfo.taskDescription.setStatusBarAppearance(
+                APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND);
+        final RelayoutParams relayoutParams = new RelayoutParams();
+
+        DesktopModeWindowDecoration.updateRelayoutParams(
+                relayoutParams,
+                mTestableContext,
+                taskInfo,
+                /* applyStartTransactionOnDraw= */ true,
+                /* shouldSetTaskPositionAndCrop */ false);
+
+        assertThat(relayoutParams.mAllowCaptionInputFallthrough).isTrue();
+    }
+
+    @Test
+    public void updateRelayoutParams_freeformButOpaque_disallowsInputFallthrough() {
+        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        taskInfo.taskDescription.setStatusBarAppearance(0);
+        final RelayoutParams relayoutParams = new RelayoutParams();
+
+        DesktopModeWindowDecoration.updateRelayoutParams(
+                relayoutParams,
+                mTestableContext,
+                taskInfo,
+                /* applyStartTransactionOnDraw= */ true,
+                /* shouldSetTaskPositionAndCrop */ false);
+
+        assertThat(relayoutParams.mAllowCaptionInputFallthrough).isFalse();
+    }
+
+    @Test
+    public void updateRelayoutParams_fullscreen_disallowsInputFallthrough() {
+        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        final RelayoutParams relayoutParams = new RelayoutParams();
+
+        DesktopModeWindowDecoration.updateRelayoutParams(
+                relayoutParams,
+                mTestableContext,
+                taskInfo,
+                /* applyStartTransactionOnDraw= */ true,
+                /* shouldSetTaskPositionAndCrop */ false);
+
+        assertThat(relayoutParams.mAllowCaptionInputFallthrough).isFalse();
+    }
+
     private void fillRoundedCornersResources(int fillValue) {
         when(mMockRoundedCornersRadiusArray.getDimensionPixelSize(anyInt(), anyInt()))
                 .thenReturn(fillValue);
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index f0c6395..49254d1 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -81,7 +81,7 @@
   std::string overlay_path(loaded_idmap->OverlayApkPath());
   auto fd = unique_fd(base::utf8::open(overlay_path.c_str(), O_RDONLY | O_CLOEXEC));
   std::unique_ptr<AssetsProvider> overlay_assets;
-  if (IsFabricatedOverlay(fd)) {
+  if (IsFabricatedOverlayName(overlay_path) && IsFabricatedOverlay(fd)) {
     // Fabricated overlays do not contain resource definitions. All of the overlay resource values
     // are defined inline in the idmap.
     overlay_assets = EmptyAssetsProvider::Create(std::move(overlay_path));
@@ -137,8 +137,7 @@
       return {};
     }
     loaded_arsc = LoadedArsc::Load(data, length, loaded_idmap.get(), property_flags);
-  } else if (loaded_idmap != nullptr &&
-      IsFabricatedOverlay(std::string(loaded_idmap->OverlayApkPath()))) {
+  } else if (loaded_idmap != nullptr && IsFabricatedOverlay(loaded_idmap->OverlayApkPath())) {
     loaded_arsc = LoadedArsc::Load(loaded_idmap.get());
   } else {
     loaded_arsc = LoadedArsc::CreateEmpty();
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index 5f98b8f..9824190 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -18,8 +18,10 @@
 
 #include "androidfw/Idmap.h"
 
+#include "android-base/file.h"
 #include "android-base/logging.h"
 #include "android-base/stringprintf.h"
+#include "android-base/utf8.h"
 #include "androidfw/misc.h"
 #include "androidfw/ResourceTypes.h"
 #include "androidfw/Util.h"
@@ -250,7 +252,12 @@
 }
 } // namespace
 
-LoadedIdmap::LoadedIdmap(std::string&& idmap_path, const Idmap_header* header,
+// O_PATH is a lightweight way of creating an FD, only exists on Linux
+#ifndef O_PATH
+#define O_PATH (0)
+#endif
+
+LoadedIdmap::LoadedIdmap(const std::string& idmap_path, const Idmap_header* header,
                          const Idmap_data_header* data_header,
                          const Idmap_target_entry* target_entries,
                          const Idmap_target_entry_inline* target_inline_entries,
@@ -267,10 +274,10 @@
       configurations_(configs),
       overlay_entries_(overlay_entries),
       string_pool_(std::move(string_pool)),
-      idmap_path_(std::move(idmap_path)),
+      idmap_fd_(android::base::utf8::open(idmap_path.c_str(), O_RDONLY|O_CLOEXEC|O_BINARY|O_PATH)),
       overlay_apk_path_(overlay_apk_path),
       target_apk_path_(target_apk_path),
-      idmap_last_mod_time_(getFileModDate(idmap_path_.data())) {}
+      idmap_last_mod_time_(getFileModDate(idmap_fd_.get())) {}
 
 std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPiece idmap_data) {
   ATRACE_CALL();
@@ -368,7 +375,7 @@
 }
 
 bool LoadedIdmap::IsUpToDate() const {
-  return idmap_last_mod_time_ == getFileModDate(idmap_path_.c_str());
+  return idmap_last_mod_time_ == getFileModDate(idmap_fd_.get());
 }
 
 }  // namespace android
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 2c99f1a..a3dd983 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -54,6 +54,8 @@
 #define INT32_MAX ((int32_t)(2147483647))
 #endif
 
+using namespace std::literals;
+
 namespace android {
 
 #if defined(_WIN32)
@@ -237,12 +239,24 @@
     fill9patchOffsets(reinterpret_cast<Res_png_9patch*>(outData));
 }
 
-bool IsFabricatedOverlay(const std::string& path) {
-  return IsFabricatedOverlay(path.c_str());
+bool IsFabricatedOverlayName(std::string_view path) {
+  static constexpr auto suffixFrro = ".frro"sv;
+  static constexpr auto suffixIdmap = ".frro@idmap"sv;
+
+  return (path.size() > suffixFrro.size() && path.ends_with(suffixFrro))
+        || (path.size() > suffixIdmap.size() && path.ends_with(suffixIdmap));
 }
 
-bool IsFabricatedOverlay(const char* path) {
-  auto fd = base::unique_fd(base::utf8::open(path, O_RDONLY|O_CLOEXEC));
+bool IsFabricatedOverlay(std::string_view path) {
+  if (!IsFabricatedOverlayName(path)) {
+    return false;
+  }
+  std::string path_copy;
+  if (path[path.size()] != '\0') {
+    path_copy.assign(path);
+    path = path_copy;
+  }
+  auto fd = base::unique_fd(base::utf8::open(path.data(), O_RDONLY|O_CLOEXEC|O_BINARY));
   if (fd < 0) {
     return false;
   }
@@ -7319,9 +7333,6 @@
 public:
     void add(uint32_t targetResId, uint32_t overlayResId) {
         uint8_t targetTypeId = Res_GETTYPE(targetResId);
-        if (mData.find(targetTypeId) == mData.end()) {
-            mData.emplace(targetTypeId, std::set<std::pair<uint32_t, uint32_t>>());
-        }
         auto& entries = mData[targetTypeId];
         entries.insert(std::make_pair(targetResId, overlayResId));
     }
diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h
index d9f7c2a..c32a38e 100644
--- a/libs/androidfw/include/androidfw/Idmap.h
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -23,6 +23,7 @@
 #include <variant>
 
 #include "android-base/macros.h"
+#include "android-base/unique_fd.h"
 #include "androidfw/ConfigDescription.h"
 #include "androidfw/StringPiece.h"
 #include "androidfw/ResourceTypes.h"
@@ -159,11 +160,6 @@
   // Loads an IDMAP from a chunk of memory. Returns nullptr if the IDMAP data was malformed.
   static std::unique_ptr<LoadedIdmap> Load(StringPiece idmap_path, StringPiece idmap_data);
 
-  // Returns the path to the IDMAP.
-  std::string_view IdmapPath() const {
-    return idmap_path_;
-  }
-
   // Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated.
   std::string_view OverlayApkPath() const {
     return overlay_apk_path_;
@@ -203,7 +199,7 @@
   const Idmap_overlay_entry* overlay_entries_;
   const std::unique_ptr<ResStringPool> string_pool_;
 
-  std::string idmap_path_;
+  android::base::unique_fd idmap_fd_;
   std::string_view overlay_apk_path_;
   std::string_view target_apk_path_;
   time_t idmap_last_mod_time_;
@@ -211,7 +207,7 @@
  private:
   DISALLOW_COPY_AND_ASSIGN(LoadedIdmap);
 
-  explicit LoadedIdmap(std::string&& idmap_path,
+  explicit LoadedIdmap(const std::string& idmap_path,
                        const Idmap_header* header,
                        const Idmap_data_header* data_header,
                        const Idmap_target_entry* target_entries,
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 3d1403d..c264890 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -59,8 +59,8 @@
 constexpr const uint32_t kFabricatedOverlayCurrentVersion = 3;
 
 // Returns whether or not the path represents a fabricated overlay.
-bool IsFabricatedOverlay(const std::string& path);
-bool IsFabricatedOverlay(const char* path);
+bool IsFabricatedOverlayName(std::string_view path);
+bool IsFabricatedOverlay(std::string_view path);
 bool IsFabricatedOverlay(android::base::borrowed_fd fd);
 
 /**
diff --git a/libs/androidfw/include/androidfw/misc.h b/libs/androidfw/include/androidfw/misc.h
index d40d24e..077609d 100644
--- a/libs/androidfw/include/androidfw/misc.h
+++ b/libs/androidfw/include/androidfw/misc.h
@@ -43,6 +43,8 @@
 FileType getFileType(const char* fileName);
 /* get the file's modification date; returns -1 w/errno set on failure */
 time_t getFileModDate(const char* fileName);
+/* same, but also returns -1 if the file has already been deleted */
+time_t getFileModDate(int fd);
 
 // Check if |path| or |fd| resides on a readonly filesystem.
 bool isReadonlyFilesystem(const char* path);
diff --git a/libs/androidfw/misc.cpp b/libs/androidfw/misc.cpp
index d3949e9..93dcaf5 100644
--- a/libs/androidfw/misc.cpp
+++ b/libs/androidfw/misc.cpp
@@ -76,13 +76,23 @@
 /*
  * Get a file's modification date.
  */
-time_t getFileModDate(const char* fileName)
-{
+time_t getFileModDate(const char* fileName) {
     struct stat sb;
+    if (stat(fileName, &sb) < 0) {
+        return (time_t)-1;
+    }
+    return sb.st_mtime;
+}
 
-    if (stat(fileName, &sb) < 0)
-        return (time_t) -1;
-
+time_t getFileModDate(int fd) {
+    struct stat sb;
+    if (fstat(fd, &sb) < 0) {
+        return (time_t)-1;
+    }
+    if (sb.st_nlink <= 0) {
+        errno = ENOENT;
+        return (time_t)-1;
+    }
     return sb.st_mtime;
 }
 
diff --git a/libs/hostgraphics/ADisplay.cpp b/libs/hostgraphics/ADisplay.cpp
new file mode 100644
index 0000000..9cc1f40
--- /dev/null
+++ b/libs/hostgraphics/ADisplay.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apex/display.h>
+#include <utils/Errors.h>
+
+namespace android::display::impl {
+
+/**
+ * Implementation of ADisplayConfig
+ */
+struct DisplayConfigImpl {
+    /**
+     * The width in pixels of the display configuration.
+     */
+    int32_t width{1080};
+
+    /**
+     * The height in pixels of the display configuration.
+     */
+
+    int32_t height{1920};
+
+    /**
+     * The refresh rate of the display configuration, in frames per second.
+     */
+    float fps{60.0};
+
+    /**
+     * The vsync offset at which surfaceflinger runs, in nanoseconds.
+     */
+    int64_t sfOffset{0};
+
+    /**
+     * The vsync offset at which applications run, in nanoseconds.
+     */
+    int64_t appOffset{0};
+};
+
+// DisplayConfigImpl allocation is not managed through C++ memory apis, so
+// preventing calling the destructor here.
+static_assert(std::is_trivially_destructible<DisplayConfigImpl>::value);
+
+/**
+ * Implementation of ADisplay
+ */
+struct DisplayImpl {
+    /**
+     * The type of the display, i.e. whether it is an internal or external
+     * display.
+     */
+    ADisplayType type;
+
+    /**
+     * The preferred WCG dataspace
+     */
+    ADataSpace wcgDataspace;
+
+    /**
+     * The preferred WCG pixel format
+     */
+    AHardwareBuffer_Format wcgPixelFormat;
+
+    /**
+     * The config for this display.
+     */
+    DisplayConfigImpl config;
+};
+
+// DisplayImpl allocation is not managed through C++ memory apis, so
+// preventing calling the destructor here.
+static_assert(std::is_trivially_destructible<DisplayImpl>::value);
+
+} // namespace android::display::impl
+
+using namespace android;
+using namespace android::display::impl;
+
+namespace android {
+
+int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays) {
+    // This is running on host, so there are no physical displays available.
+    // Create 1 fake display instead.
+    DisplayImpl** const impls = reinterpret_cast<DisplayImpl**>(
+            malloc(sizeof(DisplayImpl*) + sizeof(DisplayImpl)));
+    DisplayImpl* const displayData = reinterpret_cast<DisplayImpl*>(impls + 1);
+
+    displayData[0] = DisplayImpl{ADisplayType::DISPLAY_TYPE_INTERNAL,
+                                 ADataSpace::ADATASPACE_UNKNOWN,
+                                 AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+                                 DisplayConfigImpl()};
+    impls[0] = displayData;
+    *outDisplays = reinterpret_cast<ADisplay**>(impls);
+    return 1;
+}
+
+void ADisplay_release(ADisplay** displays) {
+    if (displays == nullptr) {
+        return;
+    }
+    free(displays);
+}
+
+float ADisplay_getMaxSupportedFps(ADisplay* display) {
+    DisplayImpl* impl = reinterpret_cast<DisplayImpl*>(display);
+    return impl->config.fps;
+}
+
+ADisplayType ADisplay_getDisplayType(ADisplay* display) {
+    return reinterpret_cast<DisplayImpl*>(display)->type;
+}
+
+void ADisplay_getPreferredWideColorFormat(ADisplay* display, ADataSpace* outDataspace,
+                                          AHardwareBuffer_Format* outPixelFormat) {
+    DisplayImpl* impl = reinterpret_cast<DisplayImpl*>(display);
+    *outDataspace = impl->wcgDataspace;
+    *outPixelFormat = impl->wcgPixelFormat;
+}
+
+int ADisplay_getCurrentConfig(ADisplay* display, ADisplayConfig** outConfig) {
+    DisplayImpl* impl = reinterpret_cast<DisplayImpl*>(display);
+    *outConfig = reinterpret_cast<ADisplayConfig*>(&impl->config);
+    return OK;
+}
+
+int32_t ADisplayConfig_getWidth(ADisplayConfig* config) {
+    return reinterpret_cast<DisplayConfigImpl*>(config)->width;
+}
+
+int32_t ADisplayConfig_getHeight(ADisplayConfig* config) {
+    return reinterpret_cast<DisplayConfigImpl*>(config)->height;
+}
+
+float ADisplayConfig_getFps(ADisplayConfig* config) {
+    return reinterpret_cast<DisplayConfigImpl*>(config)->fps;
+}
+
+int64_t ADisplayConfig_getCompositorOffsetNanos(ADisplayConfig* config) {
+    return reinterpret_cast<DisplayConfigImpl*>(config)->sfOffset;
+}
+
+int64_t ADisplayConfig_getAppVsyncOffsetNanos(ADisplayConfig* config) {
+    return reinterpret_cast<DisplayConfigImpl*>(config)->appOffset;
+}
+
+} // namespace android
diff --git a/libs/hostgraphics/Android.bp b/libs/hostgraphics/Android.bp
index f166fde..4407af6 100644
--- a/libs/hostgraphics/Android.bp
+++ b/libs/hostgraphics/Android.bp
@@ -22,6 +22,7 @@
 
     srcs: [
         ":libui_host_common",
+        "ADisplay.cpp",
         "Fence.cpp",
         "HostBufferQueue.cpp",
         "PublicFormat.cpp",
@@ -32,16 +33,21 @@
         // When frameworks/native/include will be removed from the list of automatic includes.
         // We will have to copy necessary headers with a pre-build step (generated headers).
         ".",
-        "frameworks/native/libs/nativebase/include",
-        "frameworks/native/libs/nativewindow/include",
         "frameworks/native/libs/arect/include",
         "frameworks/native/libs/ui/include_private",
     ],
+
+    header_libs: [
+        "libnativebase_headers",
+        "libnativedisplay_headers",
+        "libnativewindow_headers",
+    ],
+
     export_include_dirs: ["."],
 
     target: {
         windows: {
             enabled: true,
-        }
+        },
     },
 }
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 40239b8..54f94f5 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -346,6 +346,7 @@
         "jni/android_util_PathParser.cpp",
 
         "jni/Bitmap.cpp",
+        "jni/BitmapRegionDecoder.cpp",
         "jni/BufferUtils.cpp",
         "jni/HardwareBufferHelpers.cpp",
         "jni/BitmapFactory.cpp",
@@ -421,7 +422,6 @@
                 "jni/android_graphics_TextureLayer.cpp",
                 "jni/android_graphics_HardwareRenderer.cpp",
                 "jni/android_graphics_HardwareBufferRenderer.cpp",
-                "jni/BitmapRegionDecoder.cpp",
                 "jni/GIFMovie.cpp",
                 "jni/GraphicsStatsService.cpp",
                 "jni/Movie.cpp",
@@ -559,8 +559,13 @@
         "AnimatorManager.cpp",
         "CanvasTransform.cpp",
         "DamageAccumulator.cpp",
+        "DeviceInfo.cpp",
+        "FrameInfo.cpp",
+        "FrameInfoVisualizer.cpp",
+        "FrameMetricsReporter.cpp",
         "Gainmap.cpp",
         "Interpolator.cpp",
+        "JankTracker.cpp",
         "LightingInfo.cpp",
         "Matrix.cpp",
         "Mesh.cpp",
@@ -623,13 +628,8 @@
                 "utils/NdkUtils.cpp",
                 "AutoBackendTextureRelease.cpp",
                 "DeferredLayerUpdater.cpp",
-                "DeviceInfo.cpp",
-                "FrameInfo.cpp",
-                "FrameInfoVisualizer.cpp",
                 "HardwareBitmapUploader.cpp",
                 "HWUIProperties.sysprop",
-                "JankTracker.cpp",
-                "FrameMetricsReporter.cpp",
                 "Layer.cpp",
                 "LayerUpdateQueue.cpp",
                 "ProfileDataContainer.cpp",
@@ -643,7 +643,10 @@
             cflags: ["-Wno-implicit-fallthrough"],
         },
         host: {
-            header_libs: ["libnativebase_headers"],
+            header_libs: [
+                "libnativebase_headers",
+                "libnativedisplay_headers",
+            ],
 
             local_include_dirs: ["platform/host"],
 
@@ -655,7 +658,11 @@
                 "platform/host/WebViewFunctorManager.cpp",
             ],
 
-            cflags: ["-Wno-unused-private-field"],
+            cflags: [
+                "-DHWUI_NULL_GPU",
+                "-DNULL_GPU_MAX_TEXTURE_SIZE=4096",
+                "-Wno-unused-private-field",
+            ],
         },
     },
 }
diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in
index d21f07ef..b12486e 100644
--- a/libs/hwui/DisplayListOps.in
+++ b/libs/hwui/DisplayListOps.in
@@ -26,6 +26,7 @@
 X(ClipRect)
 X(ClipRRect)
 X(ClipRegion)
+X(ClipShader)
 X(ResetClip)
 X(DrawPaint)
 X(DrawBehind)
diff --git a/libs/hwui/FrameInfoVisualizer.cpp b/libs/hwui/FrameInfoVisualizer.cpp
index 59f2169..1e53fc2 100644
--- a/libs/hwui/FrameInfoVisualizer.cpp
+++ b/libs/hwui/FrameInfoVisualizer.cpp
@@ -249,6 +249,7 @@
 }
 
 void FrameInfoVisualizer::dumpData(int fd) {
+#ifdef __ANDROID__
     RETURN_IF_PROFILING_DISABLED();
 
     // This method logs the last N frames (where N is <= mDataSize) since the
@@ -268,6 +269,7 @@
                 durationMS(i, FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers),
                 durationMS(i, FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted));
     }
+#endif
 }
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 4b0ddd2..638a060 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -17,10 +17,10 @@
 #include "JankTracker.h"
 
 #include <cutils/ashmem.h>
+#include <cutils/trace.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <log/log.h>
-#include <sys/mman.h>
 
 #include <algorithm>
 #include <cmath>
@@ -278,7 +278,7 @@
 
 void JankTracker::dumpData(int fd, const ProfileDataDescription* description,
                            const ProfileData* data) {
-
+#ifdef __ANDROID__
     if (description) {
         switch (description->type) {
             case JankTrackerType::Generic:
@@ -296,9 +296,11 @@
     }
     data->dump(fd);
     dprintf(fd, "\n");
+#endif
 }
 
 void JankTracker::dumpFrames(int fd) {
+#ifdef __ANDROID__
     dprintf(fd, "\n\n---PROFILEDATA---\n");
     for (size_t i = 0; i < static_cast<size_t>(FrameInfoIndex::NumIndexes); i++) {
         dprintf(fd, "%s", FrameInfoNames[i]);
@@ -315,6 +317,7 @@
         }
     }
     dprintf(fd, "\n---PROFILEDATA---\n\n");
+#endif
 }
 
 void JankTracker::reset() REQUIRES(mDataMutex) {
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 3b694c5..54aef55 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -207,6 +207,13 @@
     SkClipOp op;
     void draw(SkCanvas* c, const SkMatrix&) const { c->clipRegion(region, op); }
 };
+struct ClipShader final : Op {
+    static const auto kType = Type::ClipShader;
+    ClipShader(const sk_sp<SkShader>& shader, SkClipOp op) : shader(shader), op(op) {}
+    sk_sp<SkShader> shader;
+    SkClipOp op;
+    void draw(SkCanvas* c, const SkMatrix&) const { c->clipShader(shader, op); }
+};
 struct ResetClip final : Op {
     static const auto kType = Type::ResetClip;
     ResetClip() {}
@@ -822,6 +829,9 @@
 void DisplayListData::clipRegion(const SkRegion& region, SkClipOp op) {
     this->push<ClipRegion>(0, region, op);
 }
+void DisplayListData::clipShader(const sk_sp<SkShader>& shader, SkClipOp op) {
+    this->push<ClipShader>(0, shader, op);
+}
 void DisplayListData::resetClip() {
     this->push<ResetClip>(0);
 }
@@ -1134,6 +1144,11 @@
     fDL->clipRegion(region, op);
     this->INHERITED::onClipRegion(region, op);
 }
+void RecordingCanvas::onClipShader(sk_sp<SkShader> shader, SkClipOp op) {
+    setClipMayBeComplex();
+    fDL->clipShader(shader, op);
+    this->INHERITED::onClipShader(shader, op);
+}
 void RecordingCanvas::onResetClip() {
     // This is part of "replace op" emulation, but rely on the following intersection
     // clip to potentially mark the clip as complex. If we are already complex, we do
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index afadbfd..965264f 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -140,6 +140,7 @@
     void translateZ(SkScalar);
 
     void clipPath(const SkPath&, SkClipOp, bool aa);
+    void clipShader(const sk_sp<SkShader>& shader, SkClipOp);
     void clipRect(const SkRect&, SkClipOp, bool aa);
     void clipRRect(const SkRRect&, SkClipOp, bool aa);
     void clipRegion(const SkRegion&, SkClipOp);
@@ -216,6 +217,7 @@
     void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
     void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;
     void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override;
+    void onClipShader(sk_sp<SkShader>, SkClipOp) override;
     void onClipRegion(const SkRegion&, SkClipOp) override;
     void onResetClip() override;
 
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index e358b57..b1ad8b2 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -16,10 +16,22 @@
 
 #pragma once
 
-#ifdef __ANDROID__ // Layoutlib does not support device info
-#include "DeviceInfo.h"
-#endif // __ANDROID__
+#include <SkBlendMode.h>
+#include <SkCamera.h>
+#include <SkColor.h>
+#include <SkImageFilter.h>
+#include <SkMatrix.h>
+#include <SkRegion.h>
+#include <androidfw/ResourceTypes.h>
+#include <cutils/compiler.h>
+#include <stddef.h>
+#include <utils/Log.h>
 
+#include <algorithm>
+#include <ostream>
+#include <vector>
+
+#include "DeviceInfo.h"
 #include "Outline.h"
 #include "Rect.h"
 #include "RevealClip.h"
@@ -27,21 +39,6 @@
 #include "utils/MathUtils.h"
 #include "utils/PaintUtils.h"
 
-#include <SkBlendMode.h>
-#include <SkImageFilter.h>
-#include <SkCamera.h>
-#include <SkColor.h>
-#include <SkMatrix.h>
-#include <SkRegion.h>
-
-#include <androidfw/ResourceTypes.h>
-#include <cutils/compiler.h>
-#include <stddef.h>
-#include <utils/Log.h>
-#include <algorithm>
-#include <ostream>
-#include <vector>
-
 class SkBitmap;
 class SkColorFilter;
 class SkPaint;
@@ -546,13 +543,9 @@
     }
 
     bool fitsOnLayer() const {
-#ifdef __ANDROID__ // Layoutlib does not support device info
         const DeviceInfo* deviceInfo = DeviceInfo::get();
         return mPrimitiveFields.mWidth <= deviceInfo->maxTextureSize() &&
                mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize();
-#else
-        return mPrimitiveFields.mWidth <= 4096 && mPrimitiveFields.mHeight <= 4096;
-#endif
     }
 
     bool promotedToLayer() const {
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 536ff78..2ea4e3f 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -16,6 +16,7 @@
 
 #include "VectorDrawable.h"
 
+#include <gui/TraceUtils.h>
 #include <math.h>
 #include <string.h>
 #include <utils/Log.h>
@@ -26,12 +27,7 @@
 #include "SkSamplingOptions.h"
 #include "SkScalar.h"
 #include "hwui/Paint.h"
-
-#ifdef __ANDROID__
 #include "renderthread/RenderThread.h"
-#endif
-
-#include <gui/TraceUtils.h>
 #include "utils/Macros.h"
 #include "utils/VectorDrawableUtils.h"
 
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index f84107e..f9dc5fa 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -41,6 +41,8 @@
 
 namespace {
 
+static const bool ENABLE_POINTER_CHOREOGRAPHER = input_flags::enable_pointer_choreographer();
+
 const ui::Transform kIdentityTransform;
 
 } // namespace
@@ -224,7 +226,7 @@
 
     mLocked.presentation = presentation;
 
-    if (input_flags::enable_pointer_choreographer()) {
+    if (ENABLE_POINTER_CHOREOGRAPHER) {
         // When pointer choreographer is enabled, the presentation mode is only set once when the
         // PointerController is constructed, before the display viewport is provided.
         // TODO(b/293587049): Clean up the PointerController interface after pointer choreographer
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index ea136ed..c90c441 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -1079,7 +1079,7 @@
      * @return one of the values that can be set in {@link Builder#setEncoding(int)} or
      * {@link AudioFormat#ENCODING_INVALID} if not set.
      */
-    public @Encoding int getEncoding() {
+    public @EncodingCanBeInvalid int getEncoding() {
         return mEncoding;
     }
 
@@ -1486,6 +1486,44 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface Encoding {}
 
+    /** @hide same as @Encoding, but adding ENCODING_INVALID */
+    @IntDef(flag = false, prefix = "ENCODING", value = {
+            ENCODING_INVALID,
+            ENCODING_DEFAULT,
+            ENCODING_PCM_16BIT,
+            ENCODING_PCM_8BIT,
+            ENCODING_PCM_FLOAT,
+            ENCODING_AC3,
+            ENCODING_E_AC3,
+            ENCODING_DTS,
+            ENCODING_DTS_HD,
+            ENCODING_MP3,
+            ENCODING_AAC_LC,
+            ENCODING_AAC_HE_V1,
+            ENCODING_AAC_HE_V2,
+            ENCODING_IEC61937,
+            ENCODING_DOLBY_TRUEHD,
+            ENCODING_AAC_ELD,
+            ENCODING_AAC_XHE,
+            ENCODING_AC4,
+            ENCODING_E_AC3_JOC,
+            ENCODING_DOLBY_MAT,
+            ENCODING_OPUS,
+            ENCODING_PCM_24BIT_PACKED,
+            ENCODING_PCM_32BIT,
+            ENCODING_MPEGH_BL_L3,
+            ENCODING_MPEGH_BL_L4,
+            ENCODING_MPEGH_LC_L3,
+            ENCODING_MPEGH_LC_L4,
+            ENCODING_DTS_UHD_P1,
+            ENCODING_DRA,
+            ENCODING_DTS_HD_MA,
+            ENCODING_DTS_UHD_P2,
+            ENCODING_DSD }
+    )
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EncodingCanBeInvalid {}
+
     /** @hide */
     public static final int[] SURROUND_SOUND_ENCODING = {
             ENCODING_AC3,
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 8f3f82e..6f7024a 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -7878,9 +7878,9 @@
      */
     @FlaggedApi(FLAG_SUPPORTED_DEVICE_TYPES_API)
     public @NonNull Set<Integer>
-            getSupportedDeviceTypes(int direction) {
+            getSupportedDeviceTypes(@AudioDeviceRole int direction) {
         if (direction != GET_DEVICES_OUTPUTS && direction != GET_DEVICES_INPUTS) {
-            throw new IllegalArgumentException("AudioManager.getSupportedDeviceTypes("
+            throw new IllegalArgumentException("AudioManager.getSupportedDeviceTypes(0x"
                     + Integer.toHexString(direction) + ") - Invalid.");
         }
 
diff --git a/media/java/android/media/RingtoneSelection.java b/media/java/android/media/RingtoneSelection.java
deleted file mode 100644
index b7c3721..0000000
--- a/media/java/android/media/RingtoneSelection.java
+++ /dev/null
@@ -1,742 +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 android.media;
-
-import static java.util.Objects.requireNonNull;
-
-import android.annotation.FlaggedApi;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.TestApi;
-import android.content.ContentProvider;
-import android.content.ContentResolver;
-import android.net.Uri;
-import android.os.UserHandle;
-import android.os.vibrator.Flags;
-import android.provider.MediaStore;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Objects;
-
-/**
- * Immutable representation a desired ringtone, usually originating from a user preference.
- * Unlike sound-only Uris, a "silent" setting is an explicit selection value, rather than null.
- *
- * <p>This representation can be converted into (or from) a URI form for storing within a string
- * preference or when using the ringtone picker via {@link RingtoneManager#ACTION_RINGTONE_PICKER}.
- * It does not carry any actual media data - it only references the components that make
- * up the preference. Initial selections can be built using {@link RingtoneSelection.Builder}.
- *
- * <p>A RingtoneSelection is typically played by passing into a {@link Ringtone.Builder}, and
- * supplementing with contextual defaults from the application. Bad Uris are handled by the
- * {@link Ringtone} class - the RingtoneSelection doesn't validate the target of the Uri.
- *
- * <p>When a RingtoneSelection is created/loaded, the values of its properties are modified
- * to be internally consistent and reflect effective values - with the exception of not verifying
- * the actual URI content. For example, loading a selection Uri that sets a sound source to
- * {@link #SOUND_SOURCE_URI}, but doesn't also have a sound Uri set, will result in this class
- * instead returning {@link #SOUND_SOURCE_UNSPECIFIED} from {@link #getSoundSource}.
- *
- * <h2>Storing preferences</h2>
- *
- * <p>A ringtone preference can have several states: either unset, set to a ringtone selection Uri,
- * or, from prior to the introduction of {@code RingtoneSelection}, set to a sound-only Uri or
- * explicitly set to null to indicate silent.
- *
- * @hide
- */
-@TestApi
-@FlaggedApi(Flags.FLAG_HAPTICS_CUSTOMIZATION_ENABLED)
-public final class RingtoneSelection {
-
-    /**
-     * The sound source was specified but its value was not recognized. This value is used
-     * internally for not stripping unrecognised (possibly future) values during processing.
-     * @hide
-     */
-    public static final int SOUND_SOURCE_UNKNOWN = -1;
-
-    /**
-     * The sound source is not explicitly specified, so it can follow default behavior for its
-     * context.
-     */
-    public static final int SOUND_SOURCE_UNSPECIFIED = 0;
-
-    /**
-     * Sound is explicitly disabled, such as the user having selected "Silent" in the sound picker.
-     */
-    public static final int SOUND_SOURCE_OFF = 1;
-
-    /**
-     * The sound Uri should be used as the source of sound.
-     */
-    public static final int SOUND_SOURCE_URI = 2;
-
-    /**
-     * The sound should explicitly use the system default.
-     *
-     * <p>This value isn't valid within the system default itself.
-     */
-    public static final int SOUND_SOURCE_SYSTEM_DEFAULT = 3;
-
-    // Note: Value 4 reserved for possibility of SOURCE_SOURCE_APPLICATION_DEFAULT.
-
-    /**
-     * Directive for how to make sound.
-     * @hide
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "SOUND_SOURCE_", value = {
-            SOUND_SOURCE_UNKNOWN,
-            SOUND_SOURCE_UNSPECIFIED,
-            SOUND_SOURCE_OFF,
-            SOUND_SOURCE_URI,
-            SOUND_SOURCE_SYSTEM_DEFAULT,
-    })
-    public @interface SoundSource {}
-
-    /**
-     * The vibration source was specified but its value was not recognized.
-     * This value is used internally for not stripping unrecognised (possibly
-     * future) values during processing.
-     * @hide
-     */
-    public static final int VIBRATION_SOURCE_UNKNOWN = -1;
-
-    /**
-     * Vibration source is not explicitly specified. If vibration is enabled, this will use the
-     * first available of {@link #VIBRATION_SOURCE_AUDIO_CHANNEL},
-     * {@link #VIBRATION_SOURCE_APPLICATION_DEFAULT}, or {@link #VIBRATION_SOURCE_SYSTEM_DEFAULT}.
-     */
-    public static final int VIBRATION_SOURCE_UNSPECIFIED = 0;
-
-    /** Specifies that vibration is explicitly disabled for this ringtone. */
-    public static final int VIBRATION_SOURCE_OFF = 1;
-
-    /** The vibration Uri should be used as the source of vibration. */
-    public static final int VIBRATION_SOURCE_URI = 2;
-
-    /**
-     * The vibration should explicitly use the system default.
-     *
-     * <p>This value isn't valid within the system default itself.
-     */
-    public static final int VIBRATION_SOURCE_SYSTEM_DEFAULT = 3;
-
-    /**
-     * Specifies that vibration should use the vibration provided by the application. This is
-     * typically the application's own default for the use-case, provided via
-     * {@link Ringtone.Builder#setVibrationEffect}. For notification channels, this is the vibration
-     * effect saved on the notification channel.
-     *
-     * <p>If no vibration is specified by the application, this value behaves if the source was
-     * {@link #VIBRATION_SOURCE_UNSPECIFIED}.
-     *
-     * <p>This value isn't valid within the system default.
-     */
-    public static final int VIBRATION_SOURCE_APPLICATION_DEFAULT = 4;
-
-    /**
-     * Specifies that vibration should use haptic audio channels from the
-     * sound Uri. If the sound URI doesn't have haptic channels, then reverts to the order specified
-     * by {@link #VIBRATION_SOURCE_UNSPECIFIED}.
-     */
-    // Numeric gap from VIBRATION_SOURCE_APPLICATION_DEFAULT in case we want other common elements.
-    public static final int VIBRATION_SOURCE_AUDIO_CHANNEL = 10;
-
-    /**
-     * Specifies that vibration should generate haptic audio channels from the
-     * audio tracks of the sound Uri.
-     *
-     * If the sound Uri already has haptic channels, then behaves as though
-     * {@link #VIBRATION_SOURCE_AUDIO_CHANNEL} was specified instead.
-     */
-    public static final int VIBRATION_SOURCE_HAPTIC_GENERATOR = 11;
-
-    /**
-     * Directive for how to vibrate.
-     * @hide
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "VIBRATION_SOURCE_", value = {
-            VIBRATION_SOURCE_UNKNOWN,
-            VIBRATION_SOURCE_UNSPECIFIED,
-            VIBRATION_SOURCE_OFF,
-            VIBRATION_SOURCE_URI,
-            VIBRATION_SOURCE_APPLICATION_DEFAULT,
-            VIBRATION_SOURCE_AUDIO_CHANNEL,
-            VIBRATION_SOURCE_HAPTIC_GENERATOR,
-    })
-    public @interface VibrationSource {}
-
-    /**
-     * Configures {@link #RingtoneSelection#fromUri} to treat an unrecognized Uri as the sound Uri
-     * for the returned {@link RingtoneSelection}, with null meaning {@link #SOUND_SOURCE_OFF},
-     * and symbolic default URIs ({@link RingtoneManager#getDefaultUri}) meaning
-     * {@link #SOUND_SOURCE_SYSTEM_DEFAULT}.
-     *
-     * <p>This behavior is particularly suited to loading values from older settings that may
-     * contain a raw sound Uri or null for silent.
-     *
-     * <p>An unrecognized Uri is one for which {@link #isRingtoneSelectionUri(Uri)} returns false.
-     */
-    public static final int FROM_URI_RINGTONE_SELECTION_OR_SOUND = 1;
-
-    /**
-     * Configures {@link #RingtoneSelection#fromUri} to treat an unrecognized Uri as the vibration
-     * Uri for the returned {@link RingtoneSelection}, with null meaning
-     * {@link #VIBRATION_SOURCE_OFF} and symbolic default URIs
-     * ({@link RingtoneManager#getDefaultUri}) meaning {@link #VIBRATION_SOURCE_SYSTEM_DEFAULT}.
-     *
-     * <p>An unrecognized Uri is one for which {@link #isRingtoneSelectionUri(Uri)} returns false.
-     */
-    public static final int FROM_URI_RINGTONE_SELECTION_OR_VIBRATION = 2;
-
-    /**
-     * Configures {@link #RingtoneSelection#fromUri} to treat an unrecognized Uri as an invalid
-     * value. Null or an invalid values will revert to default behavior correspnoding to
-     * {@link #DEFAULT_SELECTION_URI_STRING}. Symbolic default URIs
-     * ({@link RingtoneManager#getDefaultUri}) will set both
-     * {@link #SOUND_SOURCE_SYSTEM_DEFAULT} and {@link #VIBRATION_SOURCE_SYSTEM_DEFAULT}.
-     *
-     * <p>An unrecognized Uri is one for which {@link #isRingtoneSelectionUri(Uri)} returns false,
-     * which include {@code null}.
-     */
-    public static final int FROM_URI_RINGTONE_SELECTION_ONLY = 3;
-
-    /**
-     * How to treat values in {@link #fromUri}.
-     * @hide
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "FROM_URI_", value = {
-            FROM_URI_RINGTONE_SELECTION_OR_SOUND,
-            FROM_URI_RINGTONE_SELECTION_OR_VIBRATION,
-            FROM_URI_RINGTONE_SELECTION_ONLY
-    })
-    public @interface FromUriBehavior {}
-
-    private static final String BASE_RINGTONE_URI = "content://media/ringtone";
-    /**
-     * String representation of a RingtoneSelection Uri that says to use defaults (equivalent
-     * to {@code new RingtoneSelection.Builder().build()}).
-     */
-    public static final String DEFAULT_SELECTION_URI_STRING = BASE_RINGTONE_URI;
-
-    private static final String MEDIA_URI_RINGTONE_PATH = "/ringtone";
-
-    /* Query param keys. */
-    private static final String URI_PARAM_SOUND_URI = "su";
-    private static final String URI_PARAM_SOUND_SOURCE = "ss";
-    private static final String URI_PARAM_VIBRATION_URI = "vu";
-    private static final String URI_PARAM_VIBRATION_SOURCE = "vs";
-
-    /* Common param values */
-    private static final String SOURCE_OFF_STRING = "off";
-    private static final String SOURCE_SYSTEM_DEFAULT_STRING = "sys";
-
-    /* Vibration source param values. */
-    private static final String VIBRATION_SOURCE_AUDIO_CHANNEL_STRING = "ac";
-    private static final String VIBRATION_SOURCE_APPLICATION_DEFAULT_STRING = "app";
-    private static final String VIBRATION_SOURCE_HAPTIC_GENERATOR_STRING = "hg";
-
-    @Nullable
-    private final Uri mSoundUri;
-    @SoundSource
-    private final int mSoundSource;
-
-    @Nullable
-    private final Uri mVibrationUri;
-    @VibrationSource
-    private final int mVibrationSource;
-
-    private RingtoneSelection(@Nullable Uri soundUri, @SoundSource int soundSource,
-            @Nullable Uri vibrationUri, @VibrationSource int vibrationSource) {
-        // Enforce guarantees on the source values: revert to unspecified if they depend on
-        // something that's not set.
-        //
-        // The non-public "unknown" value can't appear in a getter result, it's just a reserved
-        // "null" value and should be treated the same as an unrecognized value. This can be seen
-        // in Uri parsing. For this and other unrecognized values, we either revert them to the URI
-        // source, if a Uri was included, or the "unspecified" source otherwise. This can be
-        // seen in action in the Uri parsing.
-        //
-        // The "unspecified" source is a public value meaning that there is no specific
-        // behavior indicated, and the defaults and fallbacks should be applied. For example, an
-        // vibration source value of "system default" means to explicitly use the system default
-        // vibration. However, an "unspecified" vibration source will first see if audio coupled
-        // or application-default vibrations are available.
-        mSoundSource = switch (soundSource) {
-            // Supported explicit values that don't have a Uri.
-            case SOUND_SOURCE_OFF, SOUND_SOURCE_UNSPECIFIED, SOUND_SOURCE_SYSTEM_DEFAULT ->
-                    soundSource;
-            // Uri and unknown/unrecognized values: use a Uri if one is present, else revert to
-            // unspecified.
-            default ->
-                soundUri != null ? SOUND_SOURCE_URI : SOUND_SOURCE_UNSPECIFIED;
-        };
-        mVibrationSource = switch (vibrationSource) {
-            // Enforce vibration sources that require a sound Uri.
-            case VIBRATION_SOURCE_AUDIO_CHANNEL, VIBRATION_SOURCE_HAPTIC_GENERATOR ->
-                    soundUri != null ? vibrationSource : VIBRATION_SOURCE_UNSPECIFIED;
-            // Supported explicit values that don't rely on any Uri.
-            case VIBRATION_SOURCE_OFF, VIBRATION_SOURCE_UNSPECIFIED,
-                    VIBRATION_SOURCE_SYSTEM_DEFAULT, VIBRATION_SOURCE_APPLICATION_DEFAULT ->
-                    vibrationSource;
-            // Uri and unknown/unrecognized values: use a Uri if one is present, else revert to
-            // unspecified.
-            default ->
-                    vibrationUri != null ? VIBRATION_SOURCE_URI : VIBRATION_SOURCE_UNSPECIFIED;
-        };
-        // Clear Uri values if they're un-used by the source.
-        mSoundUri = mSoundSource == SOUND_SOURCE_URI ? soundUri : null;
-        mVibrationUri = mVibrationSource == VIBRATION_SOURCE_URI ? vibrationUri : null;
-    }
-
-    /**
-     * Returns the stored sound behavior.
-     */
-    @SoundSource
-    public int getSoundSource() {
-        return mSoundSource;
-    }
-
-    /**
-     * Returns the sound Uri for this selection. This is guaranteed to be non-null if
-     * {@link #getSoundSource} returns {@link #SOUND_SOURCE_URI}.
-     */
-    @Nullable
-    public Uri getSoundUri() {
-        return mSoundUri;
-    }
-
-    /**
-     * Returns the selected vibration behavior.
-     */
-    @VibrationSource
-    public int getVibrationSource() {
-        return mVibrationSource;
-    }
-
-    /**
-     * Returns the vibration Uri for this selection. This is guaranteed to be non-null if
-     * {@link #getVibrationSource} returns {@link #SOUND_SOURCE_URI}.
-     */
-    @Nullable
-    public Uri getVibrationUri() {
-        return mVibrationUri;
-    }
-
-    /**
-     * Converts the ringtone selection into a Uri-form, suitable for storing as a user preference
-     * or returning as a result.
-     */
-    @NonNull
-    public Uri toUri() {
-        Uri.Builder builder = new Uri.Builder()
-                .scheme(ContentResolver.SCHEME_CONTENT)
-                .authority(MediaStore.AUTHORITY)
-                .path(MEDIA_URI_RINGTONE_PATH);
-        if (mSoundUri != null) {
-            builder.appendQueryParameter(URI_PARAM_SOUND_URI, mSoundUri.toString());
-        }
-        // Only off is explicit for sound sources
-        String soundSourceStr = soundSourceToString(mSoundSource);
-        if (soundSourceStr != null) {
-            builder.appendQueryParameter(URI_PARAM_SOUND_SOURCE, soundSourceStr);
-        }
-        if (mVibrationUri != null) {
-            builder.appendQueryParameter(URI_PARAM_VIBRATION_URI, mVibrationUri.toString());
-        }
-        String vibrationSourceStr = vibrationSourceToString(mVibrationSource);
-        if (vibrationSourceStr != null) {
-            builder.appendQueryParameter(URI_PARAM_VIBRATION_SOURCE, vibrationSourceStr);
-        }
-        return builder.build();
-    }
-
-    /**
-     * Returns true if the Uri is an encoded {@link RingtoneSelection}. This method doesn't
-     * validate the parameters of the selection.
-     *
-     * @see #fromUri
-     * @see #toUri
-     */
-    public static boolean isRingtoneSelectionUri(@Nullable Uri uri) {
-        if (uri == null) {
-            return false;
-        }
-        // Any URI content://media/ringtone
-        return ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())
-                && MediaStore.AUTHORITY.equals(
-                        ContentProvider.getAuthorityWithoutUserId(uri.getAuthority()))
-                && MEDIA_URI_RINGTONE_PATH.equals(uri.getPath());
-    }
-
-    /**
-     * Strip the specified userId from internal Uris. Non-stripped userIds will typically be
-     * for work profiles referencing system ringtones from the host user.
-     *
-     * This is only for use in RingtoneManager.
-     * @hide
-     */
-    @VisibleForTesting
-    public RingtoneSelection getWithoutUserId(int userIdToStrip) {
-        if (mSoundSource != SOUND_SOURCE_URI && mVibrationSource != VIBRATION_SOURCE_URI) {
-            return this;
-        }
-
-        // Ok if uri is null. We only replace explicit references to the specified (current) userId.
-        int soundUserId = ContentProvider.getUserIdFromUri(mSoundUri, UserHandle.USER_NULL);
-        int vibrationUserId = ContentProvider.getUserIdFromUri(mVibrationUri, UserHandle.USER_NULL);
-        boolean needToChangeSound =
-                soundUserId != UserHandle.USER_NULL && soundUserId == userIdToStrip;
-        boolean needToChangeVibration =
-                vibrationUserId != UserHandle.USER_NULL && vibrationUserId == userIdToStrip;
-
-        // Anything to do?
-        if (!needToChangeSound && !needToChangeVibration) {
-            return this;
-        }
-
-        RingtoneSelection.Builder updated = new Builder(this);
-        // The relevant uris can't be null, because they contain userIdToStrip.
-        if (needToChangeSound) {
-            // mSoundUri is not null, so the result of getUriWithoutUserId won't be null.
-            updated.setSoundSource(ContentProvider.getUriWithoutUserId(mSoundUri));
-        }
-        if (needToChangeVibration) {
-            updated.setVibrationSource(ContentProvider.getUriWithoutUserId(mVibrationUri));
-        }
-        return updated.build();
-    }
-
-    @Override
-    public String toString() {
-        return toUri().toString();
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o == this) {
-            return true;
-        }
-        if (!(o instanceof RingtoneSelection other)) {
-            return false;
-        }
-        return this.mSoundSource == other.mSoundSource
-                && this.mVibrationSource == other.mVibrationSource
-                && Objects.equals(this.mSoundUri, other.mSoundUri)
-                && Objects.equals(this.mVibrationUri, other.mVibrationUri);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mSoundSource, mVibrationSource, mSoundUri, mVibrationUri);
-    }
-
-    /**
-     * Converts a Uri into a RingtoneSelection.
-     *
-     * <p>Null values, Uris that {@link #isRingtoneSelectionUri(Uri)} returns false (except for
-     * old-style symbolic default Uris {@link RingtoneManager#getDefaultUri}) will be treated
-     * according to the behaviour specified by the {@code unrecognizedValueBehavior} parameter.
-     *
-     * <p>Symbolic default Uris (where {@link RingtoneManager#getDefaultType(Uri)} returns -1,
-     * will map sources to {@link #SOUND_SOURCE_SYSTEM_DEFAULT} and
-     * {@link #VIBRATION_SOURCE_SYSTEM_DEFAULT}.
-     *
-     * @param uri The Uri to convert, potentially null.
-     * @param unrecognizedValueBehavior indicates how to treat values for which
-     *   {@link #isRingtoneSelectionUri(Uri)} returns false (including null).
-     * @return the RingtoneSelection represented by the given uri.
-     */
-    @NonNull
-    public static RingtoneSelection fromUri(@Nullable Uri uri,
-            @FromUriBehavior int unrecognizedValueBehavior) {
-        if (isRingtoneSelectionUri(uri)) {
-            return parseRingtoneSelectionUri(uri);
-        }
-        // Old symbolic default URIs map to the sources suggested by the unrecognized behavior.
-        // It doesn't always map to both sources because the app may have its own default behavior
-        // to apply, so non-primary sources are left as unspecified, which will revert to the
-        // system default in the absence of an app default.
-        boolean isDefaultUri = RingtoneManager.getDefaultType(uri) > 0;
-        RingtoneSelection.Builder builder = new RingtoneSelection.Builder();
-        switch (unrecognizedValueBehavior) {
-            case FROM_URI_RINGTONE_SELECTION_ONLY:
-                if (isDefaultUri) {
-                    builder.setSoundSource(SOUND_SOURCE_SYSTEM_DEFAULT);
-                    builder.setVibrationSource(VIBRATION_SOURCE_SYSTEM_DEFAULT);
-                }
-                // Always return unspecified (defaults) for unrecognized ringtone selection Uris.
-                return builder.build();
-            case FROM_URI_RINGTONE_SELECTION_OR_SOUND:
-                if (uri == null) {
-                    return builder.setSoundSource(SOUND_SOURCE_OFF).build();
-                } else if (isDefaultUri) {
-                    return builder.setSoundSource(SOUND_SOURCE_SYSTEM_DEFAULT).build();
-                } else {
-                    return builder.setSoundSource(uri).build();
-                }
-            case FROM_URI_RINGTONE_SELECTION_OR_VIBRATION:
-                if (uri == null) {
-                    return builder.setVibrationSource(VIBRATION_SOURCE_OFF).build();
-                } else if (isDefaultUri) {
-                    return builder.setVibrationSource(VIBRATION_SOURCE_SYSTEM_DEFAULT).build();
-                } else {
-                    // Unlike sound, there's no legacy settings alias uri for the default.
-                    return builder.setVibrationSource(uri).build();
-                }
-            default:
-                throw new IllegalArgumentException("Unknown behavior parameter: "
-                        + unrecognizedValueBehavior);
-        }
-    }
-
-    /**
-     * Parses the Uri, which has already been checked for {@link #isRingtoneSelectionUri(Uri)}.
-     * As a special case to be more compatible, if the RingtoneSelection has a userId specified in
-     * the authority, then this is pushed down into the sound and vibration Uri, as the selection
-     * itself is agnostic.
-     */
-    @NonNull
-    private static RingtoneSelection parseRingtoneSelectionUri(@NonNull Uri uri) {
-        RingtoneSelection.Builder builder = new RingtoneSelection.Builder();
-        int soundSource = stringToSoundSource(uri.getQueryParameter(URI_PARAM_SOUND_SOURCE));
-        int vibrationSource = stringToVibrationSource(
-                uri.getQueryParameter(URI_PARAM_VIBRATION_SOURCE));
-        Uri soundUri = getParamAsUri(uri, URI_PARAM_SOUND_URI);
-        Uri vibrationUri = getParamAsUri(uri, URI_PARAM_VIBRATION_URI);
-
-        // Add userId if necessary. This won't override an existing one in the sound/vib Uris.
-        int userIdFromAuthority = ContentProvider.getUserIdFromAuthority(
-                uri.getAuthority(), UserHandle.USER_NULL);
-        if (userIdFromAuthority != UserHandle.USER_NULL) {
-            // Won't override existing user id.
-            if (soundUri != null) {
-                soundUri = ContentProvider.maybeAddUserId(soundUri, userIdFromAuthority);
-            }
-            if (vibrationUri != null) {
-                vibrationUri = ContentProvider.maybeAddUserId(vibrationUri, userIdFromAuthority);
-            }
-        }
-
-        // Set sound uri if present, but map system default Uris to the system default source.
-        if (soundUri != null) {
-            if (RingtoneManager.getDefaultType(uri) >= 0) {
-                builder.setSoundSource(SOUND_SOURCE_SYSTEM_DEFAULT);
-            } else {
-                builder.setSoundSource(soundUri);
-            }
-        }
-        if (vibrationUri != null) {
-            builder.setVibrationSource(vibrationUri);
-        }
-
-        // Don't set the source if there's a URI and the source is default, because that will
-        // override the Uri source set above. In effect, we prioritise "explicit" sources over
-        // an implicit Uri source - except for "default", which isn't really explicit.
-        if (soundSource != SOUND_SOURCE_UNSPECIFIED || soundUri == null) {
-            builder.setSoundSource(soundSource);
-        }
-        if (vibrationSource != VIBRATION_SOURCE_UNSPECIFIED || vibrationUri == null) {
-            builder.setVibrationSource(vibrationSource);
-        }
-        return builder.build();
-    }
-
-    @Nullable
-    private static Uri getParamAsUri(@NonNull Uri uri, String param) {
-        // This returns the uri-decoded value, no need to further decode.
-        String value = uri.getQueryParameter(param);
-        if (value == null) {
-            return null;
-        }
-        return Uri.parse(value);
-    }
-
-    /**
-     * Converts the {@link SoundSource} to the uri query param value for it, or null
-     * if the sound source is default, unknown, or implicit (uri).
-     */
-    @Nullable
-    private static String soundSourceToString(@SoundSource int soundSource) {
-        return switch (soundSource) {
-            case SOUND_SOURCE_OFF -> SOURCE_OFF_STRING;
-            case SOUND_SOURCE_SYSTEM_DEFAULT -> SOURCE_SYSTEM_DEFAULT_STRING;
-            default -> null;
-        };
-    }
-
-    /**
-     * Returns the sound source int corresponding to the query string value. Returns
-     * {@link #SOUND_SOURCE_UNKNOWN} if the value isn't recognised, and
-     * {@link #SOUND_SOURCE_UNSPECIFIED} if the value is {@code null} (not in the Uri).
-     */
-    @SoundSource
-    private static int stringToSoundSource(@Nullable String soundSource) {
-        if (soundSource == null) {
-            return SOUND_SOURCE_UNSPECIFIED;
-        }
-        return switch (soundSource) {
-            case SOURCE_OFF_STRING -> SOUND_SOURCE_OFF;
-            case SOURCE_SYSTEM_DEFAULT_STRING -> SOUND_SOURCE_SYSTEM_DEFAULT;
-            default -> SOUND_SOURCE_UNKNOWN;
-        };
-    }
-
-    /**
-     * Converts the {@code vibrationSource} to the uri query param value for it, or null
-     * if the vibration source is default, unknown, or implicit (uri).
-     */
-    @Nullable
-    private static String vibrationSourceToString(@VibrationSource int vibrationSource) {
-        return switch (vibrationSource) {
-            case VIBRATION_SOURCE_OFF -> SOURCE_OFF_STRING;
-            case VIBRATION_SOURCE_AUDIO_CHANNEL -> VIBRATION_SOURCE_AUDIO_CHANNEL_STRING;
-            case VIBRATION_SOURCE_HAPTIC_GENERATOR -> VIBRATION_SOURCE_HAPTIC_GENERATOR_STRING;
-            case VIBRATION_SOURCE_APPLICATION_DEFAULT ->
-                    VIBRATION_SOURCE_APPLICATION_DEFAULT_STRING;
-            case VIBRATION_SOURCE_SYSTEM_DEFAULT -> SOURCE_SYSTEM_DEFAULT_STRING;
-            default -> null;
-        };
-    }
-
-    @VibrationSource
-    private static int stringToVibrationSource(@Nullable String vibrationSource) {
-        if (vibrationSource == null) {
-            return VIBRATION_SOURCE_UNSPECIFIED;
-        }
-        return switch (vibrationSource) {
-            case SOURCE_OFF_STRING -> VIBRATION_SOURCE_OFF;
-            case SOURCE_SYSTEM_DEFAULT_STRING -> VIBRATION_SOURCE_SYSTEM_DEFAULT;
-            case VIBRATION_SOURCE_AUDIO_CHANNEL_STRING -> VIBRATION_SOURCE_AUDIO_CHANNEL;
-            case VIBRATION_SOURCE_HAPTIC_GENERATOR_STRING -> VIBRATION_SOURCE_HAPTIC_GENERATOR;
-            case VIBRATION_SOURCE_APPLICATION_DEFAULT_STRING ->
-                    VIBRATION_SOURCE_APPLICATION_DEFAULT;
-            default -> VIBRATION_SOURCE_UNKNOWN;
-        };
-    }
-
-    /**
-     * Builder for {@link RingtoneSelection}. In general, this builder will be used by interfaces
-     * allowing the user to configure their selection. Once a selection is stored as a Uri, then
-     * the RingtoneSelection can be loaded directly using {@link RingtoneSelection#fromUri}.
-     */
-    @FlaggedApi(Flags.FLAG_HAPTICS_CUSTOMIZATION_ENABLED)
-    public static final class Builder {
-        private Uri mSoundUri;
-        private Uri mVibrationUri;
-        @SoundSource private int mSoundSource = SOUND_SOURCE_UNSPECIFIED;
-        @VibrationSource private int mVibrationSource = VIBRATION_SOURCE_UNSPECIFIED;
-
-        /**
-         * Creates a new {@link RingtoneSelection} builder. A default ringtone selection has its
-         * sound and vibration source unspecified, which means they would fall back to app/system
-         * defaults.
-         */
-        public Builder() {}
-
-        /**
-         * Creates a builder initialized with the given ringtone selection.
-         */
-        public Builder(@NonNull RingtoneSelection selection) {
-            requireNonNull(selection);
-            mSoundSource = selection.getSoundSource();
-            mSoundUri = selection.getSoundUri();
-            mVibrationSource = selection.getVibrationSource();
-            mVibrationUri = selection.getVibrationUri();
-        }
-
-        /**
-         * Sets the desired sound source.
-         *
-         * <p>Values other than {@link #SOUND_SOURCE_URI} will clear any previous sound Uri.
-         * For {@link #SOUND_SOURCE_URI}, the {@link #setSoundSource(Uri)} method should be
-         * used instead, as setting it here will have no effect unless the Uri is also set.
-         */
-        @NonNull
-        public Builder setSoundSource(@SoundSource int soundSource) {
-            mSoundSource = soundSource;
-            if (soundSource != SOUND_SOURCE_URI && soundSource != SOUND_SOURCE_UNKNOWN) {
-                // Note that this means the configuration of "silent sound, but use haptic
-                // generator" is currently not supported. Future support could be added by either
-                // using the vibration uri in that case, or by having a special
-                // "setSoundUriForVibrationOnly(Uri)" method that sets sound source to off but
-                // also retains the Uri.
-                mSoundUri = null;
-            }
-            return this;
-        }
-
-        /**
-         * Sets the sound source to {@link #SOUND_SOURCE_URI}, and the sound Uri to the
-         * specified {@link Uri}.
-         */
-        @NonNull
-        public Builder setSoundSource(@NonNull Uri soundUri) {
-            // getCanonicalUri shouldn't return null. If it somehow did, then the
-            // RingtoneSelection constructor will revert this to unspecified.
-            mSoundUri = requireNonNull(soundUri).getCanonicalUri();
-            mSoundSource = SOUND_SOURCE_URI;
-            return this;
-        }
-
-        /**
-         * Sets the vibration source to the specified value.
-         *
-         * <p>Values other than {@link #VIBRATION_SOURCE_URI} will clear any previous vibration Uri.
-         * For {@link #VIBRATION_SOURCE_URI}, the {@link #setVibrationSource(Uri)} method should be
-         * used instead, as setting it here will have no effect unless the Uri is also set.
-         */
-        @NonNull
-        public Builder setVibrationSource(@VibrationSource int vibrationSource) {
-            mVibrationSource = vibrationSource;
-            if (vibrationSource != VIBRATION_SOURCE_URI
-                    && vibrationSource != VIBRATION_SOURCE_UNKNOWN) {
-                mVibrationUri = null;
-            }
-            return this;
-        }
-
-        /**
-         * Sets the vibration source to {@link #VIBRATION_SOURCE_URI}, and the vibration Uri to the
-         * specified {@link Uri}.
-         */
-        @NonNull
-        public Builder setVibrationSource(@NonNull Uri vibrationUri) {
-            // getCanonicalUri shouldn't return null. If it somehow did, then the
-            // RingtoneSelection constructor will revert this to unspecified.
-            mVibrationUri = requireNonNull(vibrationUri).getCanonicalUri();
-            mVibrationSource = VIBRATION_SOURCE_URI;
-            return this;
-        }
-
-        /**
-         * Returns the ringtone Uri that was configured.
-         */
-        @NonNull
-        public RingtoneSelection build() {
-            return new RingtoneSelection(mSoundUri, mSoundSource, mVibrationUri, mVibrationSource);
-        }
-    }
-}
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index 48b4766..60ab1a4 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -27,7 +27,9 @@
 import android.media.AudioDeviceInfo;
 import android.media.AudioFormat;
 import android.media.AudioSystem;
+import android.os.Binder;
 import android.os.Build;
+import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -52,6 +54,8 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     private int mMixType = MIX_TYPE_INVALID;
 
+    private final IBinder mToken;
+
     // written by AudioPolicy
     int mMixState = MIX_STATE_DISABLED;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -68,7 +72,7 @@
      */
     private AudioMix(@NonNull AudioMixingRule rule, @NonNull AudioFormat format,
             int routeFlags, int callbackFlags,
-            int deviceType, @Nullable String deviceAddress) {
+            int deviceType, @Nullable String deviceAddress, IBinder token) {
         mRule = Objects.requireNonNull(rule);
         mFormat = Objects.requireNonNull(format);
         mRouteFlags = routeFlags;
@@ -76,6 +80,7 @@
         mCallbackFlags = callbackFlags;
         mDeviceSystemType = deviceType;
         mDeviceAddress = (deviceAddress == null) ? new String("") : deviceAddress;
+        mToken = token;
     }
 
     // CALLBACK_FLAG_* values: keep in sync with AudioMix::kCbFlag* values defined
@@ -273,13 +278,14 @@
         return Objects.equals(this.mRouteFlags, that.mRouteFlags)
             && Objects.equals(this.mRule, that.mRule)
             && Objects.equals(this.mMixType, that.mMixType)
-            && Objects.equals(this.mFormat, that.mFormat);
+            && Objects.equals(this.mFormat, that.mFormat)
+            && Objects.equals(this.mToken, that.mToken);
     }
 
     /** @hide */
     @Override
     public int hashCode() {
-        return Objects.hash(mRouteFlags, mRule, mMixType, mFormat);
+        return Objects.hash(mRouteFlags, mRule, mMixType, mFormat, mToken);
     }
 
     @Override
@@ -298,6 +304,7 @@
         dest.writeString8(mDeviceAddress);
         mFormat.writeToParcel(dest, flags);
         mRule.writeToParcel(dest, flags);
+        dest.writeStrongBinder(mToken);
     }
 
     public static final @NonNull Parcelable.Creator<AudioMix> CREATOR = new Parcelable.Creator<>() {
@@ -317,6 +324,7 @@
             mixBuilder.setDevice(p.readInt(), p.readString8());
             mixBuilder.setFormat(AudioFormat.CREATOR.createFromParcel(p));
             mixBuilder.setMixingRule(AudioMixingRule.CREATOR.createFromParcel(p));
+            mixBuilder.setToken(p.readStrongBinder());
             return mixBuilder.build();
         }
 
@@ -339,6 +347,7 @@
         private AudioFormat mFormat = null;
         private int mRouteFlags = 0;
         private int mCallbackFlags = 0;
+        private IBinder mToken = null;
         // an AudioSystem.DEVICE_* value, not AudioDeviceInfo.TYPE_*
         private int mDeviceSystemType = AudioSystem.DEVICE_NONE;
         private String mDeviceAddress = null;
@@ -380,6 +389,15 @@
 
         /**
          * @hide
+         * Only used by AudioMix internally.
+         */
+        Builder setToken(IBinder token) {
+            mToken = token;
+            return this;
+        }
+
+        /**
+         * @hide
          * Only used by AudioPolicyConfig, not a public API.
          * @param callbackFlags which callbacks are called from native
          * @return the same Builder instance.
@@ -540,8 +558,13 @@
                     throw new IllegalArgumentException(error);
                 }
             }
+
+            if (mToken == null) {
+                mToken = new Binder();
+            }
+
             return new AudioMix(mRule, mFormat, mRouteFlags, mCallbackFlags, mDeviceSystemType,
-                    mDeviceAddress);
+                    mDeviceAddress, mToken);
         }
 
         private int getLoopbackDeviceSystemTypeForAudioMixingRule(AudioMixingRule rule) {
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index bbe461c..508c0a2b 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -337,7 +337,9 @@
 
     /**
      * Update the current configuration of the set of audio mixes by adding new ones, while
-     * keeping the policy registered.
+     * keeping the policy registered. If any of the provided audio mixes is invalid then none of
+     * the passed mixes will be registered.
+     *
      * This method can only be called on a registered policy.
      * @param mixes the list of {@link AudioMix} to add
      * @return {@link AudioManager#SUCCESS} if the change was successful, {@link AudioManager#ERROR}
@@ -375,12 +377,15 @@
     }
 
     /**
-     * Update the current configuration of the set of audio mixes by removing some, while
-     * keeping the policy registered.
-     * This method can only be called on a registered policy.
+     * Update the current configuration of the set of audio mixes for this audio policy by
+     * removing some, while keeping the policy registered. Will unregister all provided audio
+     * mixes, if possible.
+     *
+     * This method can only be called on a registered policy and only affects this current policy.
      * @param mixes the list of {@link AudioMix} to remove
      * @return {@link AudioManager#SUCCESS} if the change was successful, {@link AudioManager#ERROR}
-     *    otherwise.
+     *    otherwise. If only some of the provided audio mixes were detached but any one mix
+     *    failed to be detached, this method returns {@link AudioManager#ERROR}.
      */
     public int detachMixes(@NonNull List<AudioMix> mixes) {
         if (mixes == null) {
@@ -394,7 +399,6 @@
             for (AudioMix mix : mixes) {
                 if (mix == null) {
                     throw new IllegalArgumentException("Illegal null AudioMix in detachMixes");
-                    // TODO also check mix is currently contained in list of mixes
                 } else {
                     zeMixes.add(mix);
                 }
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index d277c7d..5e7c7c4 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -228,7 +228,7 @@
         }
     }
 
-    private void setMixRegistration(@NonNull final AudioMix mix) {
+    protected void setMixRegistration(@NonNull final AudioMix mix) {
         if (!mRegistrationId.isEmpty()) {
             if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_LOOP_BACK) ==
                     AudioMix.ROUTE_FLAG_LOOP_BACK) {
@@ -246,7 +246,9 @@
     @GuardedBy("mMixes")
     protected void add(@NonNull ArrayList<AudioMix> mixes) {
         for (AudioMix mix : mixes) {
-            setMixRegistration(mix);
+            if (mix.getRegistration() == null || mix.getRegistration().isEmpty()) {
+                setMixRegistration(mix);
+            }
             mMixes.add(mix);
         }
     }
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index d145397..ed543e6 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -519,7 +519,7 @@
 
     @Override
     public void stopPlayback(int mode) {
-        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_STOP_PLAYBACK, mode));
+        mCaller.executeOrSendMessage(mCaller.obtainMessageI(DO_STOP_PLAYBACK, mode));
     }
 
     @Override
diff --git a/media/lib/tvremote/tests/Android.bp b/media/lib/tvremote/tests/Android.bp
index f02cfc3..280c515 100644
--- a/media/lib/tvremote/tests/Android.bp
+++ b/media/lib/tvremote/tests/Android.bp
@@ -17,6 +17,7 @@
     ],
     static_libs: [
         "mockito-target-minus-junit4",
+        "androidx.test.rules",
     ],
     platform_apis: true,
     certificate: "platform",
diff --git a/media/lib/tvremote/tests/src/com/android/media/tv/remoteprovider/TvRemoteProviderTest.java b/media/lib/tvremote/tests/src/com/android/media/tv/remoteprovider/TvRemoteProviderTest.java
index e6e3939..3b38a462 100644
--- a/media/lib/tvremote/tests/src/com/android/media/tv/remoteprovider/TvRemoteProviderTest.java
+++ b/media/lib/tvremote/tests/src/com/android/media/tv/remoteprovider/TvRemoteProviderTest.java
@@ -29,7 +29,8 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import java.util.ArrayList;
 
diff --git a/media/mca/tests/Android.bp b/media/mca/tests/Android.bp
index f02b4c0..04f083d 100644
--- a/media/mca/tests/Android.bp
+++ b/media/mca/tests/Android.bp
@@ -13,7 +13,10 @@
         "android.test.runner",
         "android.test.base",
     ],
-    static_libs: ["junit"],
+    static_libs: [
+        "junit",
+        "androidx.test.rules",
+    ],
     // Include all test java files.
     srcs: ["src/**/*.java"],
     platform_apis: true,
diff --git a/media/mca/tests/src/android/camera/mediaeffects/tests/functional/EffectsVideoCapture.java b/media/mca/tests/src/android/camera/mediaeffects/tests/functional/EffectsVideoCapture.java
index 474b00f..44f98050 100644
--- a/media/mca/tests/src/android/camera/mediaeffects/tests/functional/EffectsVideoCapture.java
+++ b/media/mca/tests/src/android/camera/mediaeffects/tests/functional/EffectsVideoCapture.java
@@ -16,18 +16,19 @@
 
 package android.camera.mediaeffects.tests.functional;
 
-import android.media.filterfw.samples.CameraEffectsRecordingSample;
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Intent;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.KeyEvent;
-import android.util.Log;
-import android.content.Intent;
-import android.os.Environment;
 import android.media.MediaMetadataRetriever;
+import android.media.filterfw.samples.CameraEffectsRecordingSample;
 import android.net.Uri;
+import android.os.Environment;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import androidx.test.filters.LargeTest;
+
 import java.io.File;
 
 public class EffectsVideoCapture extends ActivityInstrumentationTestCase2
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java
index 9b643ad..022f1da 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java
@@ -16,9 +16,6 @@
 
 package com.android.mediaframeworktest.functional;
 
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.MediaNames;
-
 import android.content.Context;
 import android.hardware.Camera;
 import android.hardware.Camera.PictureCallback;
@@ -27,10 +24,14 @@
 import android.os.ConditionVariable;
 import android.os.Looper;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 import android.view.SurfaceHolder;
 
+import androidx.test.filters.LargeTest;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.MediaNames;
+
 import java.io.*;
 
 /**
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
index da106be..8f32e91 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
@@ -18,9 +18,10 @@
 
 import android.media.MediaMetadataRetriever;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
 
+import androidx.test.filters.MediumTest;
+
 import com.android.mediaframeworktest.MediaNames;
 import com.android.mediaframeworktest.MediaProfileReader;
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java
index 728e68d..83793ee 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java
@@ -16,21 +16,20 @@
 
 package com.android.mediaframeworktest.functional;
 
-import java.io.File;
-
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
-import android.util.Log;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 import com.android.mediaframeworktest.MediaFrameworkTest;
 
+import java.io.File;
+
 /*
  * System tests for the handling of mime type in the media framework.
  *
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerInvokeTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerInvokeTest.java
index 55a1545..d7d1875 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerInvokeTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerInvokeTest.java
@@ -16,17 +16,14 @@
 
 package com.android.mediaframeworktest.functional;
 
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.MediaNames;
-
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
-
 import android.media.MediaPlayer;
 import android.os.Parcel;
+import android.test.ActivityInstrumentationTestCase2;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
 
 import java.util.Calendar;
 import java.util.Random;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioEffectTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioEffectTest.java
index ab78714..6b8cbe9 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioEffectTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioEffectTest.java
@@ -16,28 +16,26 @@
 
 package com.android.mediaframeworktest.functional.audio;
 
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.MediaNames;
-import android.content.res.AssetFileDescriptor;
-import android.media.audiofx.AudioEffect;
 import android.media.AudioFormat;
 import android.media.AudioManager;
-import android.media.AudioTrack;
 import android.media.AudioRecord;
-import android.media.audiofx.EnvironmentalReverb;
-import android.media.audiofx.Equalizer;
+import android.media.AudioTrack;
 import android.media.MediaPlayer;
 import android.media.MediaRecorder;
-
+import android.media.audiofx.AudioEffect;
+import android.media.audiofx.EnvironmentalReverb;
+import android.media.audiofx.Equalizer;
 import android.os.Looper;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 
-import java.nio.ByteOrder;
+import androidx.test.filters.LargeTest;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.MediaNames;
+
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.util.UUID;
 
 /**
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java
index 3a332c6..25288e1 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java
@@ -16,16 +16,16 @@
 
 package com.android.mediaframeworktest.functional.audio;
 
-import com.android.mediaframeworktest.MediaFrameworkTest;
 import android.content.Context;
 import android.media.AudioManager;
-import android.media.MediaPlayer;
 import android.media.AudioManager.OnAudioFocusChangeListener;
 import android.os.Looper;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
 
 /**
  * Junit / Instrumentation test case for the media AudioManager api
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioTrackTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioTrackTest.java
index eac5c28..107b51d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioTrackTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioTrackTest.java
@@ -16,17 +16,15 @@
 
 package com.android.mediaframeworktest.functional.audio;
 
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.MediaNames;
-
 import android.media.AudioFormat;
 import android.media.AudioManager;
 import android.media.AudioTrack;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.LargeTest;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
 
 /**
  * Junit / Instrumentation test case for the media AudioTrack api
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaBassBoostTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaBassBoostTest.java
index 1fa5c0d..c2dd246 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaBassBoostTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaBassBoostTest.java
@@ -16,27 +16,13 @@
 
 package com.android.mediaframeworktest.functional.audio;
 
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.MediaNames;
-import com.android.mediaframeworktest.functional.EnergyProbe;
-import android.content.Context;
-import android.content.res.AssetFileDescriptor;
-import android.media.audiofx.AudioEffect;
-import android.media.AudioManager;
 import android.media.audiofx.BassBoost;
-import android.media.audiofx.Visualizer;
-import android.media.MediaPlayer;
-
-import android.os.Looper;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 
-import java.nio.ByteOrder;
-import java.nio.ByteBuffer;
-import java.util.UUID;
+import androidx.test.filters.LargeTest;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
 
 /**
  * Junit / Instrumentation test case for the media AudioTrack api
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java
index e788c17..4bbd913 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java
@@ -16,26 +16,20 @@
 
 package com.android.mediaframeworktest.functional.audio;
 
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.MediaNames;
-import com.android.mediaframeworktest.functional.EnergyProbe;
 import android.content.Context;
-import android.content.res.AssetFileDescriptor;
-import android.media.audiofx.AudioEffect;
 import android.media.AudioManager;
-import android.media.audiofx.EnvironmentalReverb;
-import android.media.audiofx.Visualizer;
 import android.media.MediaPlayer;
-
-import android.os.Looper;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+import android.media.audiofx.AudioEffect;
+import android.media.audiofx.EnvironmentalReverb;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 
-import java.nio.ByteOrder;
-import java.nio.ByteBuffer;
+import androidx.test.filters.LargeTest;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.MediaNames;
+import com.android.mediaframeworktest.functional.EnergyProbe;
+
 import java.util.UUID;
 
 /**
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEqualizerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEqualizerTest.java
index da9089d..a43f761 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEqualizerTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEqualizerTest.java
@@ -16,27 +16,13 @@
 
 package com.android.mediaframeworktest.functional.audio;
 
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.MediaNames;
-import com.android.mediaframeworktest.functional.EnergyProbe;
-import android.content.Context;
-import android.content.res.AssetFileDescriptor;
-import android.media.audiofx.AudioEffect;
-import android.media.AudioManager;
 import android.media.audiofx.Equalizer;
-import android.media.audiofx.Visualizer;
-import android.media.MediaPlayer;
-
-import android.os.Looper;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 
-import java.nio.ByteOrder;
-import java.nio.ByteBuffer;
-import java.util.UUID;
+import androidx.test.filters.LargeTest;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
 
 /**
  * Junit / Instrumentation test case for the media AudioTrack api
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java
index bc9c48d..9d3cf79 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java
@@ -16,26 +16,20 @@
 
 package com.android.mediaframeworktest.functional.audio;
 
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.MediaNames;
-import com.android.mediaframeworktest.functional.EnergyProbe;
 import android.content.Context;
-import android.content.res.AssetFileDescriptor;
-import android.media.audiofx.AudioEffect;
 import android.media.AudioManager;
-import android.media.audiofx.PresetReverb;
-import android.media.audiofx.Visualizer;
 import android.media.MediaPlayer;
-
-import android.os.Looper;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+import android.media.audiofx.AudioEffect;
+import android.media.audiofx.PresetReverb;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 
-import java.nio.ByteOrder;
-import java.nio.ByteBuffer;
+import androidx.test.filters.LargeTest;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.MediaNames;
+import com.android.mediaframeworktest.functional.EnergyProbe;
+
 import java.util.UUID;
 
 /**
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVirtualizerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVirtualizerTest.java
index 122545f..144656c 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVirtualizerTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVirtualizerTest.java
@@ -16,27 +16,13 @@
 
 package com.android.mediaframeworktest.functional.audio;
 
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.MediaNames;
-import com.android.mediaframeworktest.functional.EnergyProbe;
-import android.content.Context;
-import android.content.res.AssetFileDescriptor;
-import android.media.audiofx.AudioEffect;
-import android.media.AudioManager;
 import android.media.audiofx.Virtualizer;
-import android.media.audiofx.Visualizer;
-import android.media.MediaPlayer;
-
-import android.os.Looper;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 
-import java.nio.ByteOrder;
-import java.nio.ByteBuffer;
-import java.util.UUID;
+import androidx.test.filters.LargeTest;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
 
 /**
  * Junit / Instrumentation test case for the media AudioTrack api
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java
index abf85d7..7644954 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java
@@ -16,24 +16,20 @@
 
 package com.android.mediaframeworktest.functional.audio;
 
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.MediaNames;
 import android.content.Context;
-import android.content.res.AssetFileDescriptor;
-import android.media.audiofx.AudioEffect;
 import android.media.AudioManager;
-import android.media.audiofx.Visualizer;
 import android.media.MediaPlayer;
-
+import android.media.audiofx.AudioEffect;
+import android.media.audiofx.Visualizer;
 import android.os.Looper;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 
-import java.nio.ByteOrder;
-import java.nio.ByteBuffer;
+import androidx.test.filters.LargeTest;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.MediaNames;
+
 import java.util.UUID;
 
 /**
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/SimTonesTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/SimTonesTest.java
index aaf992c..ae42074 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/SimTonesTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/SimTonesTest.java
@@ -17,12 +17,13 @@
 package com.android.mediaframeworktest.functional.audio;
 
 // import android.content.Resources;
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.functional.TonesAutoTest;
-
 import android.content.Context;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.functional.TonesAutoTest;
 
 /**
  * Junit / Instrumentation test case for the SIM tone generator
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/camera/CameraFunctionalTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/camera/CameraFunctionalTest.java
index 9c08d48..bf5e816 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/camera/CameraFunctionalTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/camera/CameraFunctionalTest.java
@@ -16,22 +16,23 @@
 
 package com.android.mediaframeworktest.functional.camera;
 
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.helpers.CameraTestHelper;
-
-import java.io.Writer;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-import java.util.List;
-
 import android.hardware.Camera.Parameters;
 import android.os.Handler;
 import android.os.Looper;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 import android.view.SurfaceHolder;
 
+import androidx.test.filters.LargeTest;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.helpers.CameraTestHelper;
+
+import java.io.Writer;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Junit / Instrumentation test case for the following camera APIs:
  * - flash
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/camera/CameraPairwiseTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/camera/CameraPairwiseTest.java
index f9d4964..45c95e0 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/camera/CameraPairwiseTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/camera/CameraPairwiseTest.java
@@ -20,17 +20,18 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 import android.view.SurfaceHolder;
 
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-import java.util.List;
+import androidx.test.filters.LargeTest;
 
 import com.android.mediaframeworktest.MediaFrameworkTest;
 import com.android.mediaframeworktest.helpers.CameraTestHelper;
 
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Junit / Instrumentation test case for camera API pairwise testing
  * Settings tested against: flash mode, exposure compensation, white balance,
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediaplayback/MediaPlayerApiTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediaplayback/MediaPlayerApiTest.java
index 7be2707..8739820 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediaplayback/MediaPlayerApiTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediaplayback/MediaPlayerApiTest.java
@@ -16,20 +16,18 @@
 
 package com.android.mediaframeworktest.functional.mediaplayback;
 
+import android.content.Context;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 import com.android.mediaframeworktest.MediaFrameworkTest;
 import com.android.mediaframeworktest.MediaNames;
 import com.android.mediaframeworktest.MediaProfileReader;
 import com.android.mediaframeworktest.functional.CodecTest;
 
-import android.content.Context;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
-
-import java.io.File;
-
 /**
  * Junit / Instrumentation test case for the media player api
  */
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
index 35540e3..3c456fb 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
@@ -16,37 +16,32 @@
 
 package com.android.mediaframeworktest.functional.mediarecorder;
 
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.MediaNames;
-
-import java.io.*;
-
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
-import android.graphics.Typeface;
 import android.hardware.Camera;
+import android.media.EncoderCapabilities.AudioEncoderCap;
+import android.media.EncoderCapabilities.VideoEncoderCap;
 import android.media.MediaCodec;
 import android.media.MediaMetadataRetriever;
 import android.media.MediaPlayer;
 import android.media.MediaRecorder;
-import android.media.EncoderCapabilities;
-import android.media.EncoderCapabilities.VideoEncoderCap;
-import android.media.EncoderCapabilities.AudioEncoderCap;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 import android.view.Surface;
 import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import com.android.mediaframeworktest.MediaProfileReader;
+
+import androidx.test.filters.LargeTest;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
 import com.android.mediaframeworktest.MediaFrameworkTestRunner;
+import com.android.mediaframeworktest.MediaNames;
+import com.android.mediaframeworktest.MediaProfileReader;
 
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
+import java.io.*;
 import java.util.List;
 
-
 /**
  * Junit / Instrumentation test case for the media recorder api
  */
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index cc7a7d5..e89becd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -31,9 +31,10 @@
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
+import androidx.test.filters.SmallTest;
+
 /**
  * <p>
  * Junit / Instrumentation test case for the camera2 api
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 9d09dcc..eaa5a85 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -46,10 +46,11 @@
 import android.os.ServiceSpecificException;
 import android.os.SystemClock;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 import android.view.Surface;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.mediaframeworktest.MediaFrameworkIntegrationTestRunner;
 
 import org.mockito.ArgumentCaptor;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index 8c05725..0154d6a 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -16,36 +16,33 @@
 
 package com.android.mediaframeworktest.performance;
 
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.MediaFrameworkPerfTestRunner;
-import com.android.mediaframeworktest.MediaNames;
-import com.android.mediaframeworktest.MediaTestUtil;
-
-import android.database.sqlite.SQLiteDatabase;
 import android.hardware.Camera;
 import android.hardware.Camera.PreviewCallback;
 import android.media.CamcorderProfile;
 import android.media.MediaPlayer;
 import android.media.MediaRecorder;
-import android.media.EncoderCapabilities.VideoEncoderCap;
 import android.os.ConditionVariable;
 import android.os.Looper;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 import android.view.SurfaceHolder;
 
-import java.util.List;
+import androidx.test.filters.LargeTest;
+
+import com.android.mediaframeworktest.MediaFrameworkPerfTestRunner;
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.MediaNames;
+import com.android.mediaframeworktest.MediaProfileReader;
+import com.android.mediaframeworktest.MediaTestUtil;
+
 import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Writer;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.BufferedWriter;
-
-import com.android.mediaframeworktest.MediaProfileReader;
 
 /**
  * Junit / Instrumentation - performance measurement for media player and
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
index dc8da48..a47d8bc 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
@@ -43,13 +43,13 @@
 import android.media.MediaFormat;
 import android.media.MediaRecorder;
 import android.os.SystemClock;
-import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 import android.util.Range;
 import android.util.Size;
 import android.view.Surface;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
 
 import com.android.ex.camera2.blocking.BlockingSessionCallback;
 import com.android.mediaframeworktest.Camera2SurfaceViewTestCase;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2SwitchPreviewTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2SwitchPreviewTest.java
index a26ee2d..002a143 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2SwitchPreviewTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2SwitchPreviewTest.java
@@ -16,71 +16,34 @@
 
 package com.android.mediaframeworktest.stress;
 
-import com.android.ex.camera2.blocking.BlockingSessionCallback;
-import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
-import com.android.mediaframeworktest.Camera2SurfaceViewTestCase;
-import com.android.mediaframeworktest.helpers.Camera2Focuser;
-import com.android.mediaframeworktest.helpers.CameraTestUtils;
-import com.android.mediaframeworktest.helpers.CameraTestUtils.SimpleCaptureCallback;
-
-import android.graphics.ImageFormat;
-import android.graphics.Point;
-import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CameraCaptureSession.CaptureCallback;
-import android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession;
-import android.hardware.camera2.CameraDevice;
-import android.hardware.camera2.CameraAccessException;
-import android.hardware.camera2.CameraCaptureSession;
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.DngCreator;
-import android.hardware.camera2.params.MeteringRectangle;
-import android.media.Image;
-import android.media.ImageReader;
-import android.media.CamcorderProfile;
-import android.media.MediaExtractor;
-import android.media.MediaFormat;
-import android.media.MediaRecorder;
-import android.os.ConditionVariable;
-import android.os.Environment;
-import android.util.Log;
-import android.util.Pair;
-import android.util.Rational;
-import android.util.Size;
-import android.view.Surface;
-import android.hardware.camera2.params.StreamConfigurationMap;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
-import android.util.Range;
-
-import java.io.ByteArrayOutputStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.io.File;
-import java.util.Arrays;
-import java.util.HashMap;
-
-import static com.android.mediaframeworktest.helpers.CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS;
 import static com.android.mediaframeworktest.helpers.CameraTestUtils.MAX_READER_IMAGES;
-import static com.android.mediaframeworktest.helpers.CameraTestUtils.SimpleImageReaderListener;
-import static com.android.mediaframeworktest.helpers.CameraTestUtils.basicValidateJpegImage;
-import static com.android.mediaframeworktest.helpers.CameraTestUtils.configureCameraSession;
-import static com.android.mediaframeworktest.helpers.CameraTestUtils.dumpFile;
-import static com.android.mediaframeworktest.helpers.CameraTestUtils.getDataFromImage;
-import static com.android.mediaframeworktest.helpers.CameraTestUtils.getValueNotNull;
-import static com.android.mediaframeworktest.helpers.CameraTestUtils.makeImageReader;
-import static com.android.ex.camera2.blocking.BlockingSessionCallback.SESSION_CLOSED;
-import static com.android.mediaframeworktest.helpers.CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS;
-import static com.android.mediaframeworktest.helpers.CameraTestUtils.SESSION_CLOSE_TIMEOUT_MS;
 import static com.android.mediaframeworktest.helpers.CameraTestUtils.SIZE_BOUND_1080P;
 import static com.android.mediaframeworktest.helpers.CameraTestUtils.SIZE_BOUND_2160P;
+import static com.android.mediaframeworktest.helpers.CameraTestUtils.SimpleImageReaderListener;
+import static com.android.mediaframeworktest.helpers.CameraTestUtils.configureCameraSession;
 import static com.android.mediaframeworktest.helpers.CameraTestUtils.getSupportedVideoSizes;
 
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCaptureSession.CaptureCallback;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.media.CamcorderProfile;
+import android.media.ImageReader;
+import android.media.MediaRecorder;
+import android.util.Log;
+import android.util.Range;
+import android.util.Size;
+import android.view.Surface;
+
 import com.android.ex.camera2.blocking.BlockingSessionCallback;
 import com.android.mediaframeworktest.Camera2SurfaceViewTestCase;
-import com.android.mediaframeworktest.helpers.CameraTestUtils;
+import com.android.mediaframeworktest.helpers.CameraTestUtils.SimpleCaptureCallback;
 
-import junit.framework.AssertionFailedError;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
 
 /**
  * <p>Tests Back/Front camera switching and Camera/Video modes witching.</p>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/CameraStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/CameraStressTest.java
index 74244b9..9883df2e3 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/CameraStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/CameraStressTest.java
@@ -16,6 +16,16 @@
 
 package com.android.mediaframeworktest.stress;
 
+import android.hardware.Camera.Parameters;
+import android.os.Handler;
+import android.os.Looper;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+
 import com.android.mediaframeworktest.MediaFrameworkTest;
 import com.android.mediaframeworktest.helpers.CameraTestHelper;
 
@@ -23,19 +33,9 @@
 import java.io.File;
 import java.io.FileWriter;
 import java.io.Writer;
+import java.util.List;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
-import java.util.List;
-
-import android.hardware.Camera.Parameters;
-import android.os.Handler;
-import android.os.Looper;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
-import android.view.SurfaceHolder;
-
-import androidx.test.InstrumentationRegistry;
 
 /**
  * Junit / Instrumentation test case for the following camera APIs:
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStreamingStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStreamingStressTest.java
index 6a820ec..cb69e1b 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStreamingStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStreamingStressTest.java
@@ -16,16 +16,16 @@
 
 package com.android.mediaframeworktest.stress;
 
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.MediaPlayerStressTestRunner;
-
 import android.os.Bundle;
 import android.os.Environment;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
+import androidx.test.filters.LargeTest;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
 import com.android.mediaframeworktest.MediaNames;
+import com.android.mediaframeworktest.MediaPlayerStressTestRunner;
 import com.android.mediaframeworktest.functional.CodecTest;
 
 import java.io.BufferedReader;
@@ -34,7 +34,6 @@
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.Writer;
-
 import java.util.ArrayList;
 import java.util.List;
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
index 4221f1b..221881a 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
@@ -16,16 +16,16 @@
 
 package com.android.mediaframeworktest.stress;
 
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.MediaPlayerStressTestRunner;
-
 import android.os.Bundle;
 import android.os.Environment;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
+import androidx.test.filters.LargeTest;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
 import com.android.mediaframeworktest.MediaNames;
+import com.android.mediaframeworktest.MediaPlayerStressTestRunner;
 import com.android.mediaframeworktest.functional.CodecTest;
 
 import java.io.BufferedWriter;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
index 199f179..47bd633 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
@@ -17,16 +17,6 @@
 package com.android.mediaframeworktest.stress;
 
 
-import com.android.mediaframeworktest.MediaFrameworkTest;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.Writer;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
 import android.hardware.Camera;
 import android.media.CamcorderProfile;
 import android.media.MediaPlayer;
@@ -35,11 +25,22 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 import android.view.SurfaceHolder;
+
+import androidx.test.filters.LargeTest;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
 import com.android.mediaframeworktest.MediaRecorderStressTestRunner;
 
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Junit / Instrumentation test case for the media player api
  */
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/template/AudioTestHarnessTemplateAndroidTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/template/AudioTestHarnessTemplateAndroidTest.java
index 6c2a3f7..fec108f 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/template/AudioTestHarnessTemplateAndroidTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/template/AudioTestHarnessTemplateAndroidTest.java
@@ -20,9 +20,10 @@
 import android.media.MediaPlayer;
 import android.os.Bundle;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
+import androidx.test.filters.LargeTest;
+
 import com.android.mediaframeworktest.AudioTestHarnessTemplateRunner;
 import com.android.mediaframeworktest.MediaFrameworkTest;
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index c814eba..964da45 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -16,12 +16,10 @@
 
 package com.android.mediaframeworktest.unit;
 
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-import android.util.Pair;
-import android.util.Range;
-import android.util.Rational;
-import android.util.SizeF;
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+
+import static com.android.mediaframeworktest.unit.ByteArrayHelpers.*;
+
 import android.graphics.ImageFormat;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -31,7 +29,6 @@
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
-import android.util.Size;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
 import android.hardware.camera2.params.ColorSpaceTransform;
@@ -45,9 +42,14 @@
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.params.TonemapCurve;
 import android.hardware.camera2.utils.TypeReference;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Rational;
+import android.util.Size;
+import android.util.SizeF;
 
-import static android.hardware.camera2.impl.CameraMetadataNative.*;
-import static com.android.mediaframeworktest.unit.ByteArrayHelpers.*;
+import androidx.test.filters.SmallTest;
 
 import java.lang.reflect.Array;
 import java.nio.ByteBuffer;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsTypeReferenceTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsTypeReferenceTest.java
index 1b765ea..924ad47 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsTypeReferenceTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsTypeReferenceTest.java
@@ -20,8 +20,7 @@
 
 import android.hardware.camera2.utils.TypeReference;
 
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
+import androidx.test.filters.SmallTest;
 
 import java.lang.reflect.Type;
 import java.util.List;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsUncheckedThrowTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsUncheckedThrowTest.java
index b648763..6cb8b54 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsUncheckedThrowTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsUncheckedThrowTest.java
@@ -18,7 +18,8 @@
 
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.utils.UncheckedThrow;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.Assert;
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java
index 2cb5704..d9fc88d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java
@@ -24,7 +24,8 @@
 import android.media.ImageReader;
 import android.media.ImageReader.OnImageAvailableListener;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 public class ImageReaderTest extends AndroidTestCase {
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
index ea0494f..65264d3 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
@@ -36,7 +36,8 @@
 import android.provider.MediaStore.Images;
 import android.provider.MediaStore.Video;
 import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
index e3d3897..80edf8a 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
@@ -26,10 +26,10 @@
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.media.playback.flags.Flags;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetCurrentPositionStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetCurrentPositionStateUnitTest.java
index 37dd4b5..06c527d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetCurrentPositionStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetCurrentPositionStateUnitTest.java
@@ -18,7 +18,8 @@
 
 import android.media.MediaPlayer;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetDurationStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetDurationStateUnitTest.java
index 48fd16c..5a36044 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetDurationStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetDurationStateUnitTest.java
@@ -18,7 +18,8 @@
 
 import android.media.MediaPlayer;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetVideoHeightStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetVideoHeightStateUnitTest.java
index 6d3c083..f86f77e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetVideoHeightStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetVideoHeightStateUnitTest.java
@@ -18,7 +18,8 @@
 
 import android.media.MediaPlayer;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetVideoWidthStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetVideoWidthStateUnitTest.java
index 198439c..fb31edb3 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetVideoWidthStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetVideoWidthStateUnitTest.java
@@ -18,7 +18,8 @@
 
 import android.media.MediaPlayer;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerIsPlayingStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerIsPlayingStateUnitTest.java
index b9c63fd..e1c992e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerIsPlayingStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerIsPlayingStateUnitTest.java
@@ -18,7 +18,8 @@
 
 import android.media.MediaPlayer;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerMetadataParserTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerMetadataParserTest.java
index bfa3976..7aed3b7 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerMetadataParserTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerMetadataParserTest.java
@@ -18,10 +18,9 @@
 import android.media.Metadata;
 import android.os.Parcel;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
 
-import java.util.Calendar;
+import androidx.test.filters.SmallTest;
+
 import java.util.Date;
 
 /*
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerPauseStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerPauseStateUnitTest.java
index 7a96792..aa4bfe6 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerPauseStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerPauseStateUnitTest.java
@@ -18,7 +18,8 @@
 
 import android.media.MediaPlayer;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerResetStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerResetStateUnitTest.java
index 2497cd7..d8651f5 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerResetStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerResetStateUnitTest.java
@@ -18,7 +18,8 @@
 
 import android.media.MediaPlayer;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerSeekToStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerSeekToStateUnitTest.java
index 991fe9c..3bcde7f 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerSeekToStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerSeekToStateUnitTest.java
@@ -18,7 +18,8 @@
 
 import android.media.MediaPlayer;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerSetAudioStreamTypeStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerSetAudioStreamTypeStateUnitTest.java
index b984514..36e93c0 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerSetAudioStreamTypeStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerSetAudioStreamTypeStateUnitTest.java
@@ -16,10 +16,11 @@
 
 package com.android.mediaframeworktest.unit;
 
-import android.media.MediaPlayer;
 import android.media.AudioManager;
+import android.media.MediaPlayer;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerSetLoopingStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerSetLoopingStateUnitTest.java
index 17c9d8c..adb56d0f 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerSetLoopingStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerSetLoopingStateUnitTest.java
@@ -18,7 +18,8 @@
 
 import android.media.MediaPlayer;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerSetVolumeStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerSetVolumeStateUnitTest.java
index a149565..84691da 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerSetVolumeStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerSetVolumeStateUnitTest.java
@@ -18,7 +18,8 @@
 
 import android.media.MediaPlayer;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerStartStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerStartStateUnitTest.java
index 68c8e42..a0999d8 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerStartStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerStartStateUnitTest.java
@@ -18,7 +18,8 @@
 
 import android.media.MediaPlayer;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerStopStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerStopStateUnitTest.java
index ab8519a..b0673a8 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerStopStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerStopStateUnitTest.java
@@ -18,7 +18,8 @@
 
 import android.media.MediaPlayer;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderPrepareStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderPrepareStateUnitTest.java
index 134144d..8299a7e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderPrepareStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderPrepareStateUnitTest.java
@@ -18,8 +18,9 @@
 
 import android.media.MediaRecorder;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
+
 import java.io.IOException;
 
 /**
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderResetStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderResetStateUnitTest.java
index cae9e31..1e4c060 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderResetStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderResetStateUnitTest.java
@@ -18,8 +18,8 @@
 
 import android.media.MediaRecorder;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioEncoderStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioEncoderStateUnitTest.java
index 4b5a818..b3e9009d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioEncoderStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioEncoderStateUnitTest.java
@@ -18,8 +18,8 @@
 
 import android.media.MediaRecorder;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioSourceStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioSourceStateUnitTest.java
index f8ab48cf..3b56e6f 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioSourceStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioSourceStateUnitTest.java
@@ -18,8 +18,8 @@
 
 import android.media.MediaRecorder;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFileStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFileStateUnitTest.java
index 712a758..0980802 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFileStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFileStateUnitTest.java
@@ -18,8 +18,8 @@
 
 import android.media.MediaRecorder;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFormatStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFormatStateUnitTest.java
index cacdd87..3a4a7c7 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFormatStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFormatStateUnitTest.java
@@ -18,8 +18,8 @@
 
 import android.media.MediaRecorder;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStartStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStartStateUnitTest.java
index d1232fc..192c896 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStartStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStartStateUnitTest.java
@@ -18,8 +18,8 @@
 
 import android.media.MediaRecorder;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
 
 /**
  * Unit test class to test the set of valid and invalid states that
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStopStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStopStateUnitTest.java
index 91100ae..093ed88 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStopStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStopStateUnitTest.java
@@ -18,10 +18,10 @@
 
 import android.media.MediaRecorder;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 
+import androidx.test.filters.MediumTest;
+
 /**
  * Unit test class to test the set of valid and invalid states that
  * MediaRecorder.stop() method can be called.
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RangeTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RangeTest.java
index 9dd2732..f54f06d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RangeTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RangeTest.java
@@ -16,10 +16,11 @@
 
 package com.android.mediaframeworktest.unit;
 
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Range;
 import android.util.Rational;
 
+import androidx.test.filters.SmallTest;
+
 /**
  * <pre>
  * adb shell am instrument \
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
index 1bb7db9..a94b5af 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
@@ -16,9 +16,12 @@
 
 package com.android.mediaframeworktest.unit;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import static android.util.Rational.*;
+
 import android.util.Rational;
 
+import androidx.test.filters.SmallTest;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -28,8 +31,6 @@
 import java.io.Serializable;
 import java.lang.reflect.Field;
 
-import static android.util.Rational.*;
-
 /**
  * <pre>
  * adb shell am instrument \
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/SurfaceUtilsTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/SurfaceUtilsTest.java
index f578e46..cd564b2 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/SurfaceUtilsTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/SurfaceUtilsTest.java
@@ -19,9 +19,10 @@
 import android.graphics.ImageFormat;
 import android.hardware.camera2.utils.SurfaceUtils;
 import android.media.ImageReader;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.Surface;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.Assert;
 
 public class SurfaceUtilsTest extends junit.framework.TestCase {
diff --git a/media/tests/projection/Android.bp b/media/tests/projection/Android.bp
index c9a8864..fd5f195 100644
--- a/media/tests/projection/Android.bp
+++ b/media/tests/projection/Android.bp
@@ -3,6 +3,7 @@
 //########################################################################
 
 package {
+    default_team: "trendy_team_lse_desktop_os_experience",
     // 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"
diff --git a/nfc/api/current.txt b/nfc/api/current.txt
index 0fb7c95..9d0221a 100644
--- a/nfc/api/current.txt
+++ b/nfc/api/current.txt
@@ -206,9 +206,9 @@
     method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>);
     method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String, boolean);
     method public boolean removeAidsForService(android.content.ComponentName, String);
-    method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setDefaultToObserveModeForService(@NonNull android.content.ComponentName, boolean);
     method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String);
     method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
+    method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setShouldDefaultToObserveModeForService(@NonNull android.content.ComponentName, boolean);
     method public boolean supportsAidPrefixRegistration();
     method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean unsetOffHostForService(@NonNull android.content.ComponentName);
     method public boolean unsetPreferredService(android.app.Activity);
diff --git a/nfc/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl
index 64f7fa4..85a07b7 100644
--- a/nfc/java/android/nfc/INfcCardEmulation.aidl
+++ b/nfc/java/android/nfc/INfcCardEmulation.aidl
@@ -30,7 +30,7 @@
     boolean isDefaultServiceForAid(int userHandle, in ComponentName service, String aid);
     boolean setDefaultServiceForCategory(int userHandle, in ComponentName service, String category);
     boolean setDefaultForNextTap(int userHandle, in ComponentName service);
-    boolean setDefaultToObserveModeForService(int userId, in android.content.ComponentName service, boolean enable);
+    boolean setShouldDefaultToObserveModeForService(int userId, in android.content.ComponentName service, boolean enable);
     boolean registerAidGroupForService(int userHandle, in ComponentName service, in AidGroup aidGroup);
     boolean registerPollingLoopFilterForService(int userHandle, in ComponentName service, in String pollingLoopFilter, boolean autoTransact);
     boolean setOffHostForService(int userHandle, in ComponentName service, in String offHostSecureElement);
diff --git a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
index e62e37b..2c7d61e 100644
--- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -141,7 +141,7 @@
     /**
      * Whether the NFC stack should default to Observe Mode when this preferred service.
      */
-    private boolean mDefaultToObserveMode;
+    private boolean mShouldDefaultToObserveMode;
 
     /**
      * @hide
@@ -275,8 +275,8 @@
                         com.android.internal.R.styleable.HostApduService_settingsActivity);
                 mOffHostName = null;
                 mStaticOffHostName = mOffHostName;
-                mDefaultToObserveMode = sa.getBoolean(
-                        R.styleable.HostApduService_defaultToObserveMode,
+                mShouldDefaultToObserveMode = sa.getBoolean(
+                        R.styleable.HostApduService_shouldDefaultToObserveMode,
                         false);
                 sa.recycle();
             } else {
@@ -297,8 +297,8 @@
                         com.android.internal.R.styleable.HostApduService_settingsActivity);
                 mOffHostName = sa.getString(
                         com.android.internal.R.styleable.OffHostApduService_secureElementName);
-                mDefaultToObserveMode = sa.getBoolean(
-                        R.styleable.HostApduService_defaultToObserveMode,
+                mShouldDefaultToObserveMode = sa.getBoolean(
+                        R.styleable.HostApduService_shouldDefaultToObserveMode,
                         false);
                 if (mOffHostName != null) {
                     if (mOffHostName.equals("eSE")) {
@@ -633,22 +633,22 @@
     }
 
     /**
-     * Returns whether the NFC stack should default to observe mode when this servise is preferred.
-     * @return whether the NFC stack should default to observe mode when this servise is preferred
+     * Returns whether the NFC stack should default to observe mode when this service is preferred.
+     * @return whether the NFC stack should default to observe mode when this service is preferred
      */
     @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
-    public boolean defaultToObserveMode() {
-        return mDefaultToObserveMode;
+    public boolean shouldDefaultToObserveMode() {
+        return mShouldDefaultToObserveMode;
     }
 
     /**
-     * Sets whether the NFC stack should default to observe mode when this servise is preferred.
-     * @param defaultToObserveMode whether the NFC stack should default to observe mode when this
-     *                             servise is preferred
+     * Sets whether the NFC stack should default to observe mode when this service is preferred.
+     * @param shouldDefaultToObserveMode whether the NFC stack should default to observe mode when
+     *                                  this service is preferred
      */
     @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
-    public void setDefaultToObserveMode(boolean defaultToObserveMode) {
-        mDefaultToObserveMode = defaultToObserveMode;
+    public void setShouldDefaultToObserveMode(boolean shouldDefaultToObserveMode) {
+        mShouldDefaultToObserveMode = shouldDefaultToObserveMode;
     }
 
     /**
diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index 47ddd9d..ea58504 100644
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -348,11 +348,11 @@
      * @return whether the change was successful.
      */
     @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
-    public boolean setDefaultToObserveModeForService(@NonNull ComponentName service,
+    public boolean setShouldDefaultToObserveModeForService(@NonNull ComponentName service,
             boolean enable) {
         try {
-            return sService.setDefaultToObserveModeForService(mContext.getUser().getIdentifier(),
-                    service, enable);
+            return sService.setShouldDefaultToObserveModeForService(
+                    mContext.getUser().getIdentifier(), service, enable);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to reach CardEmulationService.");
         }
diff --git a/nfc/java/android/nfc/cardemulation/PollingFrame.java b/nfc/java/android/nfc/cardemulation/PollingFrame.java
index 3383f3b..994f4ae 100644
--- a/nfc/java/android/nfc/cardemulation/PollingFrame.java
+++ b/nfc/java/android/nfc/cardemulation/PollingFrame.java
@@ -201,7 +201,7 @@
 
     /**
      * Returns the timestamp of when the polling loop frame was observed in milliseconds. These
-     * timestamps are relative and not absolute and should only be used fro comparing the timing of
+     * timestamps are relative and not absolute and should only be used for comparing the timing of
      * frames relative to each other.
      * @return the timestamp in milliseconds
      */
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index bc3ad06..d910f2f 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -72,6 +72,6 @@
     <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="permission_nearby_device_streaming_summary" msgid="8280824871197081246">"Strøm apper og andre systemfunksjoner fra telefonen"</string>
     <string name="permission_media_routing_control_summary" msgid="2714631092321412250">"Se en liste over tilgjengelige enheter, og kontroller hvilken enhet som strømmer eller caster lyd eller video fra andre apper"</string>
-    <string name="device_type" product="default" msgid="8268703872070046263">"telefonen"</string>
-    <string name="device_type" product="tablet" msgid="5038791954983067774">"nettbrettet"</string>
+    <string name="device_type" product="default" msgid="8268703872070046263">"telefon"</string>
+    <string name="device_type" product="tablet" msgid="5038791954983067774">"nettbrett"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 66282dc..4c1f631 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -27,13 +27,13 @@
 
 import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState;
 import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState.FINISHED_TIMEOUT;
-import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_PERMISSIONS;
-import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_NAMES;
 import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_ICONS;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_NAMES;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_PERMISSIONS;
 import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_SUMMARIES;
+import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_TITLES;
 import static com.android.companiondevicemanager.CompanionDeviceResources.SUPPORTED_PROFILES;
 import static com.android.companiondevicemanager.CompanionDeviceResources.SUPPORTED_SELF_MANAGED_PROFILES;
-import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_TITLES;
 import static com.android.companiondevicemanager.Utils.getApplicationLabel;
 import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
 import static com.android.companiondevicemanager.Utils.getIcon;
@@ -68,6 +68,7 @@
 import android.util.Log;
 import android.view.View;
 import android.view.ViewTreeObserver;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.Button;
 import android.widget.ImageButton;
 import android.widget.ImageView;
@@ -697,14 +698,15 @@
 
         disableButtons();
 
+        LinearLayoutManager permissionListLayoutManager =
+                (LinearLayoutManager) mPermissionListRecyclerView
+                        .getLayoutManager();
+
         // Enable buttons once users scroll down to the bottom of the permission list.
         mPermissionListRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
             @Override
-            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-                super.onScrollStateChanged(recyclerView, newState);
-                if (!recyclerView.canScrollVertically(1)) {
-                    enableButtons();
-                }
+            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
+                enableAllowButtonIfNeeded(permissionListLayoutManager);
             }
         });
         // Enable buttons if last item in the permission list is visible to the users when
@@ -713,26 +715,36 @@
                 new ViewTreeObserver.OnGlobalLayoutListener() {
                     @Override
                     public void onGlobalLayout() {
-                        LinearLayoutManager layoutManager =
-                                (LinearLayoutManager) mPermissionListRecyclerView
-                                        .getLayoutManager();
-                        int lastVisibleItemPosition =
-                                layoutManager.findLastCompletelyVisibleItemPosition();
-                        int numItems = mPermissionListRecyclerView.getAdapter().getItemCount();
-
-                        if (lastVisibleItemPosition >= numItems - 1) {
-                            enableButtons();
-                        }
-
+                        enableAllowButtonIfNeeded(permissionListLayoutManager);
                         mPermissionListRecyclerView.getViewTreeObserver()
                                 .removeOnGlobalLayoutListener(this);
                     }
                 });
 
+        // Set accessibility for the recyclerView that to be able scroll up/down for voice access.
+        mPermissionListRecyclerView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
+            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+                super.onInitializeAccessibilityNodeInfo(host, info);
+                info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_DOWN);
+                info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP);
+            }
+        });
+
         mConstraintList.setVisibility(View.VISIBLE);
         mPermissionListRecyclerView.setVisibility(View.VISIBLE);
     }
 
+    // Enable the Allow button if the last element in the PermissionListRecyclerView is reached.
+    private void enableAllowButtonIfNeeded(LinearLayoutManager layoutManager) {
+        int lastVisibleItemPosition =
+                layoutManager.findLastCompletelyVisibleItemPosition();
+        int numItems = mPermissionListRecyclerView.getAdapter().getItemCount();
+
+        if (lastVisibleItemPosition >= numItems - 1) {
+            enableButtons();
+        }
+    }
+
     // Disable and grey out the Allow and Don't allow buttons if the last permission in the
     // permission list is not visible to the users.
     private void disableButtons() {
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityAnnotations.java b/packages/Connectivity/framework/src/android/net/ConnectivityAnnotations.java
deleted file mode 100644
index eb1faa0..0000000
--- a/packages/Connectivity/framework/src/android/net/ConnectivityAnnotations.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Type annotations for constants used in the connectivity API surface.
- *
- * The annotations are maintained in a separate class so that it can be built as
- * a separate library that other modules can build against, as Typedef should not
- * be exposed as SystemApi.
- *
- * @hide
- */
-public final class ConnectivityAnnotations {
-    private ConnectivityAnnotations() {}
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true, value = {
-            ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER,
-            ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY,
-            ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE,
-    })
-    public @interface MultipathPreference {}
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = false, value = {
-            ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED,
-            ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED,
-            ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED,
-    })
-    public @interface RestrictBackgroundStatus {}
-}
diff --git a/packages/CrashRecovery/framework/Android.bp b/packages/CrashRecovery/framework/Android.bp
index c0d93531..9480327 100644
--- a/packages/CrashRecovery/framework/Android.bp
+++ b/packages/CrashRecovery/framework/Android.bp
@@ -3,7 +3,7 @@
     module_type: "filegroup",
     config_namespace: "ANDROID",
     bool_variables: [
-        "move_crashrecovery_files",
+        "crashrecovery_files_in_platform",
     ],
     properties: [
         "srcs",
@@ -12,14 +12,13 @@
 
 platform_filegroup {
     name: "framework-crashrecovery-sources",
-    srcs: [
-        "java/**/*.java",
-        "java/**/*.aidl",
-    ],
     soong_config_variables: {
-        // if the flag is enabled, then files would be moved to module
-        move_crashrecovery_files: {
-            srcs: [],
+        // if this flag is enabled, then files are part of platform
+        crashrecovery_files_in_platform: {
+            srcs: [
+                "java/**/*.java",
+                "java/**/*.aidl",
+            ],
         },
     },
     path: "java",
@@ -31,7 +30,7 @@
     module_type: "filegroup",
     config_namespace: "ANDROID",
     bool_variables: [
-        "move_crashrecovery_files",
+        "crashrecovery_files_in_module",
     ],
     properties: [
         "srcs",
@@ -40,10 +39,9 @@
 
 module_filegroup {
     name: "framework-crashrecovery-module-sources",
-    srcs: [],
     soong_config_variables: {
-        // if the flag is enabled, then files would be moved to module
-        move_crashrecovery_files: {
+        // if this flag is enabled, then files are part of module
+        crashrecovery_files_in_module: {
             srcs: [
                 "java/**/*.java",
                 "java/**/*.aidl",
diff --git a/packages/CrashRecovery/services/Android.bp b/packages/CrashRecovery/services/Android.bp
index ab10b5a..961b41f 100644
--- a/packages/CrashRecovery/services/Android.bp
+++ b/packages/CrashRecovery/services/Android.bp
@@ -3,7 +3,7 @@
     module_type: "filegroup",
     config_namespace: "ANDROID",
     bool_variables: [
-        "move_crashrecovery_files",
+        "crashrecovery_files_in_platform",
     ],
     properties: [
         "srcs",
@@ -12,15 +12,14 @@
 
 platform_filegroup {
     name: "services-crashrecovery-sources",
-    srcs: [
-        "java/**/*.java",
-        "java/**/*.aidl",
-        ":statslog-crashrecovery-java-gen",
-    ],
     soong_config_variables: {
-        // if the flag is enabled, then files would be moved to module
-        move_crashrecovery_files: {
-            srcs: [],
+        // if this flag is enabled, then files are part of platform
+        crashrecovery_files_in_platform: {
+            srcs: [
+                "java/**/*.java",
+                "java/**/*.aidl",
+                ":statslog-crashrecovery-java-gen",
+            ],
         },
     },
     visibility: ["//frameworks/base:__subpackages__"],
@@ -31,7 +30,7 @@
     module_type: "filegroup",
     config_namespace: "ANDROID",
     bool_variables: [
-        "move_crashrecovery_files",
+        "crashrecovery_files_in_module",
     ],
     properties: [
         "srcs",
@@ -40,10 +39,9 @@
 
 module_filegroup {
     name: "services-crashrecovery-module-sources",
-    srcs: [],
     soong_config_variables: {
-        // if the flag is enabled, then files would be moved to module
-        move_crashrecovery_files: {
+        // if this flag is enabled, then files are part of module
+        crashrecovery_files_in_module: {
             srcs: [
                 "java/**/*.java",
                 "java/**/*.aidl",
diff --git a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
index ce8fb65..5d71b7d 100644
--- a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
+++ b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
@@ -38,13 +38,13 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
+import android.util.BackgroundThread;
 import android.util.LongArrayQueue;
 import android.util.Slog;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.XmlUtils;
 import com.android.modules.utils.TypedXmlPullParser;
diff --git a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 5fb47dd..0fb9327 100644
--- a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -75,6 +75,9 @@
     private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
             | ApplicationInfo.FLAG_SYSTEM;
 
+    private static final String PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG =
+            "persist.device_config.configuration.disable_high_impact_rollback";
+
     private final Context mContext;
     private final Handler mHandler;
     private final ApexManager mApexManager;
@@ -605,6 +608,10 @@
             // Apply all available low impact rollbacks.
             mHandler.post(() -> rollbackAllLowImpact(availableRollbacks, rollbackReason));
         } else if (minRollbackImpactLevel == PackageManager.ROLLBACK_USER_IMPACT_HIGH) {
+            // Check disable_high_impact_rollback device config before performing rollback
+            if (SystemProperties.getBoolean(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, false)) {
+                return;
+            }
             // Rollback one package at a time. If that doesn't resolve the issue, rollback
             // next with same impact level.
             mHandler.post(() -> rollbackHighImpact(availableRollbacks, rollbackReason));
@@ -718,7 +725,9 @@
                 impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_70;
                 break;
             case PackageManager.ROLLBACK_USER_IMPACT_HIGH:
-                impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_90;
+                if (!SystemProperties.getBoolean(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, false)) {
+                    impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_90;
+                }
                 break;
             default:
                 impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
diff --git a/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java b/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java
new file mode 100644
index 0000000..a6ae68f
--- /dev/null
+++ b/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java
@@ -0,0 +1,103 @@
+/*
+ *  * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Thread for asynchronous event processing. This thread is configured as
+ * {@link android.os.Process#THREAD_PRIORITY_BACKGROUND}, which means fewer CPU
+ * resources will be dedicated to it, and it will "have less chance of impacting
+ * the responsiveness of the user interface."
+ * <p>
+ * This thread is best suited for tasks that the user is not actively waiting
+ * for, or for tasks that the user expects to be executed eventually.
+ *
+ * @see com.android.internal.os.BackgroundThread
+ *
+ * TODO: b/326916057 depend on modules-utils-backgroundthread instead
+ * @hide
+ */
+public final class BackgroundThread extends HandlerThread {
+    private static final Object sLock = new Object();
+
+    @GuardedBy("sLock")
+    private static BackgroundThread sInstance;
+    @GuardedBy("sLock")
+    private static Handler sHandler;
+    @GuardedBy("sLock")
+    private static HandlerExecutor sHandlerExecutor;
+
+    private BackgroundThread() {
+        super(BackgroundThread.class.getName(), android.os.Process.THREAD_PRIORITY_BACKGROUND);
+    }
+
+    @GuardedBy("sLock")
+    private static void ensureThreadLocked() {
+        if (sInstance == null) {
+            sInstance = new BackgroundThread();
+            sInstance.start();
+            sHandler = new Handler(sInstance.getLooper());
+            sHandlerExecutor = new HandlerExecutor(sHandler);
+        }
+    }
+
+    /**
+     * Get the singleton instance of this class.
+     *
+     * @return the singleton instance of this class
+     */
+    @NonNull
+    public static BackgroundThread get() {
+        synchronized (sLock) {
+            ensureThreadLocked();
+            return sInstance;
+        }
+    }
+
+    /**
+     * Get the singleton {@link Handler} for this class.
+     *
+     * @return the singleton {@link Handler} for this class.
+     */
+    @NonNull
+    public static Handler getHandler() {
+        synchronized (sLock) {
+            ensureThreadLocked();
+            return sHandler;
+        }
+    }
+
+    /**
+     * Get the singleton {@link Executor} for this class.
+     *
+     * @return the singleton {@link Executor} for this class.
+     */
+    @NonNull
+    public static Executor getExecutor() {
+        synchronized (sLock) {
+            ensureThreadLocked();
+            return sHandlerExecutor;
+        }
+    }
+}
diff --git a/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java b/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java
new file mode 100644
index 0000000..948ebcca
--- /dev/null
+++ b/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+/**
+ * An adapter {@link Executor} that posts all executed tasks onto the given
+ * {@link Handler}.
+ *
+ * TODO: b/326916057 depend on modules-utils-backgroundthread instead
+ * @hide
+ */
+public class HandlerExecutor implements Executor {
+    private final Handler mHandler;
+
+    public HandlerExecutor(@NonNull Handler handler) {
+        mHandler = Objects.requireNonNull(handler);
+    }
+
+    @Override
+    public void execute(Runnable command) {
+        if (!mHandler.post(command)) {
+            throw new RejectedExecutionException(mHandler + " is shutting down");
+        }
+    }
+}
diff --git a/packages/CredentialManager/res/drawable/ic_passkey_24.xml b/packages/CredentialManager/res/drawable/ic_passkey_24.xml
index a2c4f37..5298f9e 100644
--- a/packages/CredentialManager/res/drawable/ic_passkey_24.xml
+++ b/packages/CredentialManager/res/drawable/ic_passkey_24.xml
@@ -13,16 +13,14 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-
-<vector
-    android:alpha="0.8"
-    android:height="24dp"
-    android:viewportHeight="24"
-    android:viewportWidth="24"
-    android:width="24dp"
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools">
-  <path android:fillColor="#4C463C" android:fillType="evenOdd" android:pathData="M22.18,14.09C22.18,15.364 21.408,16.459 20.306,16.931L21.247,17.872L20.219,18.9L21.247,19.928L19.068,22.107L18.099,21.138L18.099,17.017C16.878,16.604 16,15.45 16,14.09C16,12.383 17.383,11 19.09,11C20.796,11 22.18,12.383 22.18,14.09ZM20.692,14.091C20.692,14.976 19.975,15.693 19.09,15.693C18.205,15.693 17.488,14.976 17.488,14.091C17.488,13.206 18.205,12.488 19.09,12.488C19.975,12.488 20.692,13.206 20.692,14.091Z"/>
-  <path android:fillColor="#4C463C" android:pathData="M14.978,8.476C14.978,10.865 13.041,12.802 10.652,12.802C8.263,12.802 6.326,10.865 6.326,8.476C6.326,6.087 8.263,4.15 10.652,4.15C13.041,4.15 14.978,6.087 14.978,8.476Z"/>
-  <path android:fillColor="#4C463C" android:pathData="M2,19.263C2,16.39 7.762,14.937 10.652,14.937C11.782,14.937 13.353,15.16 14.845,15.602C15.177,16.491 15.804,17.236 16.607,17.717V21.454H2V19.263Z"/>
+<!--LINT.IfChange-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="960"
+        android:viewportHeight="960">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M120,800L120,688Q120,654 137.5,625.5Q155,597 184,582Q246,551 310,535.5Q374,520 440,520Q460,520 480,521.5Q500,523 520,526Q516,584 541,635.5Q566,687 614,720L614,800L120,800ZM760,920L700,860L700,674Q656,661 628,624.5Q600,588 600,540Q600,482 641,441Q682,400 740,400Q798,400 839,441Q880,482 880,540Q880,585 854.5,620Q829,655 790,670L840,720L780,780L840,840L760,920ZM440,480Q374,480 327,433Q280,386 280,320Q280,254 327,207Q374,160 440,160Q506,160 553,207Q600,254 600,320Q600,386 553,433Q506,480 440,480ZM740,560Q757,560 768.5,548.5Q780,537 780,520Q780,503 768.5,491.5Q757,480 740,480Q723,480 711.5,491.5Q700,503 700,520Q700,537 711.5,548.5Q723,560 740,560Z"/>
 </vector>
+<!--LINT.ThenChange(/packages/CredentialManager/shared/res/drawable/ic_passkey_24.xml)-->
\ No newline at end of file
diff --git a/packages/CredentialManager/res/values-af/strings.xml b/packages/CredentialManager/res/values-af/strings.xml
index 6c46ffc..b9ed4a2 100644
--- a/packages/CredentialManager/res/values-af/strings.xml
+++ b/packages/CredentialManager/res/values-af/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Wagwoorde sal steeds saam met toegangsleutels beskikbaar wees terwyl ons na ’n wagwoordlose toekoms beweeg."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Kies waar om jou <xliff:g id="CREATETYPES">%1$s</xliff:g> te stoor"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Kies ’n wagwoordbestuurder om jou inligting te stoor en volgende keer vinniger aan te meld"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Skep toegangsleutel vir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Stoor wagwoord vir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Stoor aanmeldinligting vir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"toegangsleutel"</string>
     <string name="password" msgid="6738570945182936667">"wagwoord"</string>
diff --git a/packages/CredentialManager/res/values-am/strings.xml b/packages/CredentialManager/res/values-am/strings.xml
index 6d65fe1..e1ded6a 100644
--- a/packages/CredentialManager/res/values-am/strings.xml
+++ b/packages/CredentialManager/res/values-am/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"ወደ የይለፍ ቃል የሌለው ወደፊት ስንሄድ የይለፍ ቃላት ከይለፍ ቁልፎች ጎን ለጎን ይገኛሉ።"</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"የእርስዎን <xliff:g id="CREATETYPES">%1$s</xliff:g> የት እንደሚያስቀምጡ ይምረጡ"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"መረጃዎን ለማስቀመጥ እና በቀጣይ ጊዜ በፍጥነት በመለያ ለመግባት የሚስጥር ቁልፍ አስተዳዳሪን ይምረጡ"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"ለ<xliff:g id="APPNAME">%1$s</xliff:g> የይለፍ ቁልፍ ይፈጠር?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"ለ<xliff:g id="APPNAME">%1$s</xliff:g> የይለፍ ቃል ይቀመጥ?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"ለ<xliff:g id="APPNAME">%1$s</xliff:g> የመግቢያ መረጃ ይቀመጥ?"</string>
     <string name="passkey" msgid="632353688396759522">"የይለፍ ቁልፍ"</string>
     <string name="password" msgid="6738570945182936667">"የይለፍ ቃል"</string>
diff --git a/packages/CredentialManager/res/values-ar/strings.xml b/packages/CredentialManager/res/values-ar/strings.xml
index 654d5b6..be55469 100644
--- a/packages/CredentialManager/res/values-ar/strings.xml
+++ b/packages/CredentialManager/res/values-ar/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"بينما ننطلق نحو مستقبل بدون كلمات مرور، ستظل كلمات المرور متوفّرة إلى جانب مفاتيح المرور."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"اختيار المكان الذي تريد حفظ <xliff:g id="CREATETYPES">%1$s</xliff:g> فيه"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"اختَر مدير كلمات مرور لحفظ معلوماتك وتسجيل الدخول بشكل أسرع في المرة القادمة."</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"هل تريد إنشاء مفتاح مرور لتطبيق \"<xliff:g id="APPNAME">%1$s</xliff:g>\"؟"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"هل تريد حفظ كلمة المرور لتطبيق \"<xliff:g id="APPNAME">%1$s</xliff:g>\"؟"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"هل تريد حفظ معلومات تسجيل الدخول لتطبيق \"<xliff:g id="APPNAME">%1$s</xliff:g>\"؟"</string>
     <string name="passkey" msgid="632353688396759522">"مفتاح المرور"</string>
     <string name="password" msgid="6738570945182936667">"كلمة المرور"</string>
diff --git a/packages/CredentialManager/res/values-as/strings.xml b/packages/CredentialManager/res/values-as/strings.xml
index 9ab41dd..6b02ea7 100644
--- a/packages/CredentialManager/res/values-as/strings.xml
+++ b/packages/CredentialManager/res/values-as/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"আমি পাছৱৰ্ডবিহীন ভৱিষ্যতৰ দিশে আগবঢ়াৰ লগে লগে পাছকীৰ লগতে পাছৱৰ্ডসমূহো উপলব্ধ হ’ব।"</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"আপোনাৰ <xliff:g id="CREATETYPES">%1$s</xliff:g> ক’ত ছেভ কৰিব লাগে সেয়া বাছনি কৰক"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"আপোনাৰ তথ্য ছেভ কৰি পৰৱৰ্তী সময়ত দ্ৰুতভাৱে ছাইন ইন কৰিবলৈ এটা পাছৱৰ্ড পৰিচালক বাছনি কৰক"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g>ৰ বাবে পাছকী সৃষ্টি কৰিবনে?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g>ৰ বাবে পাছৱৰ্ড ছেভ কৰিবনে?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g>ৰ বাবে ছাইন ইনৰ তথ্য ছেভ কৰিবনে?"</string>
     <string name="passkey" msgid="632353688396759522">"পাছকী"</string>
     <string name="password" msgid="6738570945182936667">"পাছৱৰ্ড"</string>
diff --git a/packages/CredentialManager/res/values-az/strings.xml b/packages/CredentialManager/res/values-az/strings.xml
index 67efc8b..caef727 100644
--- a/packages/CredentialManager/res/values-az/strings.xml
+++ b/packages/CredentialManager/res/values-az/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Parolsuz gələcəyə doğru irəlilədikcə parollar hələ də açarlar ilə yanaşı əlçatan olacaq."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> elementinin saxlanacağı yeri seçin"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Məlumatlarınızı yadda saxlamaq və növbəti dəfə daha sürətli daxil olmaq üçün parol meneceri seçin"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> üçün giriş açarı yaradılsın?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> üçün parol yadda saxlanılsın?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> üçün giriş məlumatları yadda saxlansın?"</string>
     <string name="passkey" msgid="632353688396759522">"açar"</string>
     <string name="password" msgid="6738570945182936667">"parol"</string>
diff --git a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
index e01e8a3..0248a08 100644
--- a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Kako se krećemo ka budućnosti bez lozinki, lozinke će i dalje biti dostupne uz pristupne kodove."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Odaberite gde ćete sačuvati: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Izaberite menadžera lozinki da biste sačuvali podatke i brže se prijavili sledeći put"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Želite da napravite pristupni kôd za: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Želite da sačuvate lozinku za: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Želite da sačuvate podatke za prijavljivanje za: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"pristupni kôd"</string>
     <string name="password" msgid="6738570945182936667">"lozinka"</string>
diff --git a/packages/CredentialManager/res/values-be/strings.xml b/packages/CredentialManager/res/values-be/strings.xml
index e7fe622..cc841d1 100644
--- a/packages/CredentialManager/res/values-be/strings.xml
+++ b/packages/CredentialManager/res/values-be/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Хоць мы ўжо рухаемся ў бок будучыні без выкарыстання пароляў, яны па-ранейшаму застануцца даступнымі нароўні з ключамі доступу."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Выберыце, куды захаваць <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Выберыце менеджар пароляў, каб захаваць свае даныя і забяспечыць хуткі ўваход у наступныя разы"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Стварыце ключ доступу да праграмы \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Захаваць пароль для праграмы \"<xliff:g id="APPNAME">%1$s</xliff:g>\"?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Захаваць інфармацыю пра спосаб уваходу ў праграму \"<xliff:g id="APPNAME">%1$s</xliff:g>\"?"</string>
     <string name="passkey" msgid="632353688396759522">"ключ доступу"</string>
     <string name="password" msgid="6738570945182936667">"пароль"</string>
diff --git a/packages/CredentialManager/res/values-bg/strings.xml b/packages/CredentialManager/res/values-bg/strings.xml
index 9b5255ef..e7027c1 100644
--- a/packages/CredentialManager/res/values-bg/strings.xml
+++ b/packages/CredentialManager/res/values-bg/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Паролите ще продължат да са налице заедно с ключовете за достъп по пътя ни към бъдеще без пароли."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Изберете къде да запазите своите <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Изберете мениджър на пароли, в който да се запазят данните ви, така че следващия път да влезете по-бързо в профила си"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Да се създаде ли код за достъп за <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Да се запази ли паролата за <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Да се запазят ли данните за вход за <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"код за достъп"</string>
     <string name="password" msgid="6738570945182936667">"парола"</string>
diff --git a/packages/CredentialManager/res/values-bn/strings.xml b/packages/CredentialManager/res/values-bn/strings.xml
index 981431c..49eb68c 100644
--- a/packages/CredentialManager/res/values-bn/strings.xml
+++ b/packages/CredentialManager/res/values-bn/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"আমরা পাসওয়ার্ডবিহীন ভবিষ্যতের দিকে এগিয়ে গেলেও, এখনও \'পাসকী\'-এর পাশাপাশি পাসওয়ার্ড ব্যবহার করা যাবে।"</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"আপনার <xliff:g id="CREATETYPES">%1$s</xliff:g> কোথায় সেভ করবেন তা বেছে নিন"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"আপনার তথ্য সেভ করতে একটি Password Manager বেছে নিন এবং পরের বার আরও দ্রুত সাইন-ইন করুন"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g>-এর জন্য \'পাসকী\' তৈরি করবেন?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g>-এর জন্য পাসওয়ার্ড সেভ করবেন?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g>-এর জন্য সাইন-ইন সংক্রান্ত তথ্য সেভ করবেন?"</string>
     <string name="passkey" msgid="632353688396759522">"পাসকী"</string>
     <string name="password" msgid="6738570945182936667">"পাসওয়ার্ড"</string>
diff --git a/packages/CredentialManager/res/values-bs/strings.xml b/packages/CredentialManager/res/values-bs/strings.xml
index 2e51625..afa4882 100644
--- a/packages/CredentialManager/res/values-bs/strings.xml
+++ b/packages/CredentialManager/res/values-bs/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Kako se krećemo prema budućnosti bez lozinki, lozinke će i dalje biti dostupne uz pristupne ključeve."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Odaberite gdje će se pohranjivati <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Odaberite upravitelja lozinki da sačuvate svoje informacije i brže se prijavite sljedeći put"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Kreirati pristupni ključ za aplikaciju <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Sačuvati lozinku za aplikaciju <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Sačuvati informacije o prijavi za aplikaciju <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"pristupni ključ"</string>
     <string name="password" msgid="6738570945182936667">"lozinka"</string>
diff --git a/packages/CredentialManager/res/values-ca/strings.xml b/packages/CredentialManager/res/values-ca/strings.xml
index 97d758c..c937c09 100644
--- a/packages/CredentialManager/res/values-ca/strings.xml
+++ b/packages/CredentialManager/res/values-ca/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Tot i que avancem cap a un futur sense contrasenyes, continuaran estant disponibles juntament amb les claus d\'accés."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Tria on vols desar les <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Selecciona un gestor de contrasenyes per desar la teva informació i iniciar la sessió més ràpidament la pròxima vegada"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Vols crear la clau d\'accés per a <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Vols desar la contrasenya per a <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vols desar la informació d\'inici de sessió per a <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"clau d\'accés"</string>
     <string name="password" msgid="6738570945182936667">"contrasenya"</string>
diff --git a/packages/CredentialManager/res/values-cs/strings.xml b/packages/CredentialManager/res/values-cs/strings.xml
index c317c92..06a81b0 100644
--- a/packages/CredentialManager/res/values-cs/strings.xml
+++ b/packages/CredentialManager/res/values-cs/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Ačkoliv směřujeme k budoucnosti bez hesel, vedle přístupových klíčů budou stále k dispozici i hesla."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Určete, kam ukládat <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Vyberte správce hesel k uložení svých údajů, abyste se příště mohli přihlásit rychleji"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Vytvořit přístupový klíč pro aplikaci <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Uložit heslo pro aplikaci <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Uložit přihlašovací údaje pro aplikaci <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"přístupový klíč"</string>
     <string name="password" msgid="6738570945182936667">"heslo"</string>
diff --git a/packages/CredentialManager/res/values-da/strings.xml b/packages/CredentialManager/res/values-da/strings.xml
index cc6b12a..207c33c 100644
--- a/packages/CredentialManager/res/values-da/strings.xml
+++ b/packages/CredentialManager/res/values-da/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Selvom vi nærmer os en fremtid, hvor adgangskoder er mindre fremtrædende, kan de stadig bruges i samspil med adgangsnøgler."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Vælg, hvor du vil gemme dine <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Vælg en adgangskodeadministrator for at gemme dine oplysninger, så du kan logge ind hurtigere næste gang"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Vil du oprette en adgangsnøgle til <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Vil du gemme adgangskoden til <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vil du gemme loginoplysningerne til <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"adgangsnøgle"</string>
     <string name="password" msgid="6738570945182936667">"adgangskode"</string>
diff --git a/packages/CredentialManager/res/values-de/strings.xml b/packages/CredentialManager/res/values-de/strings.xml
index 0dbde65..38fa3e9 100644
--- a/packages/CredentialManager/res/values-de/strings.xml
+++ b/packages/CredentialManager/res/values-de/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Auch wenn wir uns auf eine passwortlose Zukunft zubewegen, werden neben Passkeys weiter Passwörter verfügbar sein."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Wähle aus, wo deine <xliff:g id="CREATETYPES">%1$s</xliff:g> gespeichert werden sollen"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Du kannst einen Passwortmanager auswählen, um deine Anmeldedaten zu speichern, damit du dich nächstes Mal schneller anmelden kannst"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Passkey für <xliff:g id="APPNAME">%1$s</xliff:g> erstellen?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Passwort für <xliff:g id="APPNAME">%1$s</xliff:g> speichern?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Anmeldedaten für <xliff:g id="APPNAME">%1$s</xliff:g> speichern?"</string>
     <string name="passkey" msgid="632353688396759522">"Passkey"</string>
     <string name="password" msgid="6738570945182936667">"Passwort"</string>
diff --git a/packages/CredentialManager/res/values-el/strings.xml b/packages/CredentialManager/res/values-el/strings.xml
index c2a2863..509cfe6 100644
--- a/packages/CredentialManager/res/values-el/strings.xml
+++ b/packages/CredentialManager/res/values-el/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Καθώς κινούμαστε προς ένα μέλλον χωρίς κωδικούς πρόσβασης, οι κωδικοί πρόσβασης θα εξακολουθούν να είναι διαθέσιμοι μαζί με τα κλειδιά πρόσβασης."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Επιλέξτε πού θα αποθηκεύονται τα <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Επιλέξτε ένα πρόγραμμα διαχείρισης κωδικών πρόσβασης για να αποθηκεύσετε τα στοιχεία σας και να συνδεθείτε πιο γρήγορα την επόμενη φορά."</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Δημιουργία κλειδιού πρόσβασης για <xliff:g id="APPNAME">%1$s</xliff:g>;"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Αποθήκευση κωδικού πρόσβασης για <xliff:g id="APPNAME">%1$s</xliff:g>;"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Αποθήκευση στοιχείων σύνδεσης για <xliff:g id="APPNAME">%1$s</xliff:g>;"</string>
     <string name="passkey" msgid="632353688396759522">"κλειδί πρόσβασης"</string>
     <string name="password" msgid="6738570945182936667">"κωδικός πρόσβασης"</string>
diff --git a/packages/CredentialManager/res/values-en-rAU/strings.xml b/packages/CredentialManager/res/values-en-rAU/strings.xml
index 7ae0583..cd63b41 100644
--- a/packages/CredentialManager/res/values-en-rAU/strings.xml
+++ b/packages/CredentialManager/res/values-en-rAU/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"As we move towards a passwordless future, passwords will still be available alongside passkeys."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Choose where to save your <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Select a password manager to save your info and sign in faster next time"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Create passkey for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Save password for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Save sign-in info for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"passkey"</string>
     <string name="password" msgid="6738570945182936667">"password"</string>
diff --git a/packages/CredentialManager/res/values-en-rCA/strings.xml b/packages/CredentialManager/res/values-en-rCA/strings.xml
index 195f12f..ff1de20 100644
--- a/packages/CredentialManager/res/values-en-rCA/strings.xml
+++ b/packages/CredentialManager/res/values-en-rCA/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"As we move towards a passwordless future, passwords will still be available alongside passkeys."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Choose where to save your <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Select a password manager to save your info and sign in faster next time"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Create passkey for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Save password for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Save sign-in info for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"passkey"</string>
     <string name="password" msgid="6738570945182936667">"password"</string>
diff --git a/packages/CredentialManager/res/values-en-rGB/strings.xml b/packages/CredentialManager/res/values-en-rGB/strings.xml
index 7ae0583..cd63b41 100644
--- a/packages/CredentialManager/res/values-en-rGB/strings.xml
+++ b/packages/CredentialManager/res/values-en-rGB/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"As we move towards a passwordless future, passwords will still be available alongside passkeys."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Choose where to save your <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Select a password manager to save your info and sign in faster next time"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Create passkey for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Save password for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Save sign-in info for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"passkey"</string>
     <string name="password" msgid="6738570945182936667">"password"</string>
diff --git a/packages/CredentialManager/res/values-en-rIN/strings.xml b/packages/CredentialManager/res/values-en-rIN/strings.xml
index 7ae0583..cd63b41 100644
--- a/packages/CredentialManager/res/values-en-rIN/strings.xml
+++ b/packages/CredentialManager/res/values-en-rIN/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"As we move towards a passwordless future, passwords will still be available alongside passkeys."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Choose where to save your <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Select a password manager to save your info and sign in faster next time"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Create passkey for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Save password for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Save sign-in info for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"passkey"</string>
     <string name="password" msgid="6738570945182936667">"password"</string>
diff --git a/packages/CredentialManager/res/values-en-rXC/strings.xml b/packages/CredentialManager/res/values-en-rXC/strings.xml
index 5949607..8ffe001 100644
--- a/packages/CredentialManager/res/values-en-rXC/strings.xml
+++ b/packages/CredentialManager/res/values-en-rXC/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‏‏‎‎‏‏‏‏‏‏‎‎‎‎‎‏‎‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎As we move towards a passwordless future, passwords will still be available alongside passkeys.‎‏‎‎‏‎"</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‏‏‎‎‏‎‏‏‎‏‎‏‎‏‏‎‎‏‏‎‏‎‎‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‏‎‎‎‎‏‏‎‎‎Choose where to save your ‎‏‎‎‏‏‎<xliff:g id="CREATETYPES">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‏‏‏‎‎‎‎‏‎‏‎‎‎‎‏‎‏‏‎‎‏‎‏‎‏‎‎Select a password manager to save your info and sign in faster next time‎‏‎‎‏‎"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‏‎‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎Create passkey for ‎‏‎‎‏‏‎<xliff:g id="APPNAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‏‏‎Save password for ‎‏‎‎‏‏‎<xliff:g id="APPNAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‏‎‎‏‏‎‎‏‏‎‎‎‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‎‏‎Save sign-in info for ‎‏‎‎‏‏‎<xliff:g id="APPNAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
     <string name="passkey" msgid="632353688396759522">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‎‎‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‎‏‎‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‏‎‎‎‏‎‎passkey‎‏‎‎‏‎"</string>
     <string name="password" msgid="6738570945182936667">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‏‏‎‏‏‎‏‎‎‏‎‎‏‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‏‏‎‎‏‎‏‏‎‏‏‎password‎‏‎‎‏‎"</string>
diff --git a/packages/CredentialManager/res/values-es-rUS/strings.xml b/packages/CredentialManager/res/values-es-rUS/strings.xml
index f42693e..29fb64d 100644
--- a/packages/CredentialManager/res/values-es-rUS/strings.xml
+++ b/packages/CredentialManager/res/values-es-rUS/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"A medida que avanzamos hacia un futuro sin contraseñas, estas seguirán estando disponibles junto a las llaves de acceso."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Elige dónde guardar tus <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Selecciona un administrador de contraseñas para guardar tu información y acceder más rápido la próxima vez"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"¿Quieres crear una llave de acceso para <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"¿Quieres guardar la contraseña para <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"¿Quieres guardar la información de acceso para <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"llave de acceso"</string>
     <string name="password" msgid="6738570945182936667">"contraseña"</string>
diff --git a/packages/CredentialManager/res/values-es/strings.xml b/packages/CredentialManager/res/values-es/strings.xml
index 7e16e20..077ea99 100644
--- a/packages/CredentialManager/res/values-es/strings.xml
+++ b/packages/CredentialManager/res/values-es/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Aunque nos dirigimos hacia un mundo sin contraseñas, estas seguirán estando disponibles junto con las llaves de acceso."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Elige dónde guardar tus <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Selecciona un gestor de contraseñas para guardar tu información e iniciar sesión más rápido la próxima vez"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"¿Crear llave de acceso para <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"¿Guardar la contraseña de <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"¿Guardar la información de inicio de sesión de <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"llave de acceso"</string>
     <string name="password" msgid="6738570945182936667">"contraseña"</string>
diff --git a/packages/CredentialManager/res/values-et/strings.xml b/packages/CredentialManager/res/values-et/strings.xml
index 0ae48b4..6de564b 100644
--- a/packages/CredentialManager/res/values-et/strings.xml
+++ b/packages/CredentialManager/res/values-et/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Liikudes paroolivaba tuleviku poole, jäävad paroolid pääsuvõtmete kõrval siiski kättesaadavaks."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Valige, kuhu soovite oma <xliff:g id="CREATETYPES">%1$s</xliff:g> salvestada"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Valige paroolihaldur, et salvestada oma teave ja järgmisel korral kiiremini sisse logida"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Kas luua rakenduse <xliff:g id="APPNAME">%1$s</xliff:g> jaoks pääsuvõti?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Kas salvestada rakenduse <xliff:g id="APPNAME">%1$s</xliff:g> jaoks parool?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Kas salvestada rakenduse <xliff:g id="APPNAME">%1$s</xliff:g> jaoks sisselogimisandmed?"</string>
     <string name="passkey" msgid="632353688396759522">"pääsuvõti"</string>
     <string name="password" msgid="6738570945182936667">"parool"</string>
diff --git a/packages/CredentialManager/res/values-eu/strings.xml b/packages/CredentialManager/res/values-eu/strings.xml
index 8775c87..018968c 100644
--- a/packages/CredentialManager/res/values-eu/strings.xml
+++ b/packages/CredentialManager/res/values-eu/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Pasahitzik gabeko etorkizun baterantz goazen arren, pasahitzek sarbide-gakoen bizikide izaten jarraituko dute."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Aukeratu non gorde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Hautatu informazioa gordetzeko pasahitz-kudeatzaile bat eta hasi saioa bizkorrago hurrengoan"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> atzitzeko sarbide-gako bat sortu nahi duzu?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> aplikazioko pasahitza gorde nahi duzu?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> aplikazioko saioa hasteko informazioa gorde nahi duzu?"</string>
     <string name="passkey" msgid="632353688396759522">"sarbide-gakoa"</string>
     <string name="password" msgid="6738570945182936667">"pasahitza"</string>
diff --git a/packages/CredentialManager/res/values-fa/strings.xml b/packages/CredentialManager/res/values-fa/strings.xml
index 381c61e..55a79d8 100644
--- a/packages/CredentialManager/res/values-fa/strings.xml
+++ b/packages/CredentialManager/res/values-fa/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"درحالی‌که به‌سوی آینده‌ای بی‌گذرواژه حرکت می‌کنیم، گذرواژه‌ها همچنان در کنار گذرکلیدها دردسترس خواهند بود"</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"جایی را برای ذخیره کردن <xliff:g id="CREATETYPES">%1$s</xliff:g> انتخاب کنید"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"مدیر گذرواژه‌ای انتخاب کنید تا اطلاعاتتان را ذخیره کنید و دفعه بعد سریع‌تر به سیستم وارد شوید"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"برای <xliff:g id="APPNAME">%1$s</xliff:g> گذرکلید ایجاد شود؟"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"گذرواژه <xliff:g id="APPNAME">%1$s</xliff:g> ذخیره شود؟"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"اطلاعات ورود به سیستم <xliff:g id="APPNAME">%1$s</xliff:g> ذخیره شود؟"</string>
     <string name="passkey" msgid="632353688396759522">"گذرکلید"</string>
     <string name="password" msgid="6738570945182936667">"گذرواژه"</string>
diff --git a/packages/CredentialManager/res/values-fi/strings.xml b/packages/CredentialManager/res/values-fi/strings.xml
index 3c1c596..9f95720 100644
--- a/packages/CredentialManager/res/values-fi/strings.xml
+++ b/packages/CredentialManager/res/values-fi/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Kehitys kulkee kohti salasanatonta tulevaisuutta, mutta salasanat ovat edelleen käytettävissä avainkoodien ohella."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Valitse, minne <xliff:g id="CREATETYPES">%1$s</xliff:g> tallennetaan"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Valitse salasanojen ylläpitotyökalu, niin voit tallentaa tietosi ja kirjautua ensi kerralla nopeammin sisään"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Luodaanko avainkoodi (<xliff:g id="APPNAME">%1$s</xliff:g>)?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Tallennetaanko salasana (<xliff:g id="APPNAME">%1$s</xliff:g>)?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Tallennetaanko kirjautumistiedot (<xliff:g id="APPNAME">%1$s</xliff:g>)?"</string>
     <string name="passkey" msgid="632353688396759522">"avainkoodi"</string>
     <string name="password" msgid="6738570945182936667">"salasana"</string>
diff --git a/packages/CredentialManager/res/values-fr-rCA/strings.xml b/packages/CredentialManager/res/values-fr-rCA/strings.xml
index ff95af2..481fac9 100644
--- a/packages/CredentialManager/res/values-fr-rCA/strings.xml
+++ b/packages/CredentialManager/res/values-fr-rCA/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"À mesure que nous nous dirigeons vers un avenir sans mot de passe, ils resteront toujours utilisés parallèlement aux clés d\'accès."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Choisir où enregistrer vos <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Sélectionnez un gestionnaire de mots de passe pour enregistrer vos renseignements et vous connecter plus rapidement la prochaine fois"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Créer une clé d\'accès pour <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Enregistrer le mot de passe pour <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Enregistrer les renseignements de connexion pour <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"clé d\'accès"</string>
     <string name="password" msgid="6738570945182936667">"mot de passe"</string>
diff --git a/packages/CredentialManager/res/values-fr/strings.xml b/packages/CredentialManager/res/values-fr/strings.xml
index d393912..37df7fb 100644
--- a/packages/CredentialManager/res/values-fr/strings.xml
+++ b/packages/CredentialManager/res/values-fr/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Nous nous dirigeons vers un futur sans mots de passe, mais ceux-ci resteront disponibles en plus des clés d\'accès."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Choisissez où enregistrer vos <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Sélectionnez un gestionnaire de mots de passe pour enregistrer vos informations et vous connecter plus rapidement la prochaine fois"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Créer une clé d\'accès pour <xliff:g id="APPNAME">%1$s</xliff:g> ?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Enregistrer le mot de passe pour <xliff:g id="APPNAME">%1$s</xliff:g> ?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Enregistrer les informations de connexion pour <xliff:g id="APPNAME">%1$s</xliff:g> ?"</string>
     <string name="passkey" msgid="632353688396759522">"clé d\'accès"</string>
     <string name="password" msgid="6738570945182936667">"mot de passe"</string>
diff --git a/packages/CredentialManager/res/values-gl/strings.xml b/packages/CredentialManager/res/values-gl/strings.xml
index d3c8222..8770465 100644
--- a/packages/CredentialManager/res/values-gl/strings.xml
+++ b/packages/CredentialManager/res/values-gl/strings.xml
@@ -17,7 +17,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="4539824758261855508">"Xestor de credenciais"</string>
+    <string name="app_name" msgid="4539824758261855508">"Credential Manager"</string>
     <string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
     <string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
     <string name="string_more_options" msgid="2763852250269945472">"Gardar doutro xeito"</string>
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Durante este percorrido cara a un futuro sen contrasinais, estes seguirán estando dispoñibles a canda as claves de acceso."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Escolle onde queres gardar: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Selecciona un xestor de contrasinais para gardar a túa información e iniciar sesión máis rápido a próxima vez"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Queres crear unha clave de acceso para <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Queres gardar o contrasinal de <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Queres gardar a información de inicio de sesión de <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"clave de acceso"</string>
     <string name="password" msgid="6738570945182936667">"contrasinal"</string>
diff --git a/packages/CredentialManager/res/values-gu/strings.xml b/packages/CredentialManager/res/values-gu/strings.xml
index 3d4da84..efc88c1 100644
--- a/packages/CredentialManager/res/values-gu/strings.xml
+++ b/packages/CredentialManager/res/values-gu/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"આપણે પાસવર્ડ રહિત ભવિષ્ય તરફ આગળ વધી રહ્યાં છીએ, છતાં પાસકીની સાથોસાથ હજી પણ પાસવર્ડ ઉપલબ્ધ રહેશે."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"તમારી <xliff:g id="CREATETYPES">%1$s</xliff:g> ક્યાં સાચવવી તે પસંદ કરો"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"તમારી માહિતી સાચવવા માટે પાસવર્ડ મેનેજર પસંદ કરો અને આગલી વખતે વધુ ઝડપથી સાઇન ઇન કરો"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> માટે પાસકી બનાવીએ?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> માટે પાસવર્ડ સાચવીએ?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> માટે સાઇન-ઇન કરવાની માહિતી સાચવીએ?"</string>
     <string name="passkey" msgid="632353688396759522">"પાસકી"</string>
     <string name="password" msgid="6738570945182936667">"પાસવર્ડ"</string>
diff --git a/packages/CredentialManager/res/values-hi/strings.xml b/packages/CredentialManager/res/values-hi/strings.xml
index 672a852..661a4a2 100644
--- a/packages/CredentialManager/res/values-hi/strings.xml
+++ b/packages/CredentialManager/res/values-hi/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"आने वाले समय में बिना पासवर्ड वाली टेक्नोलॉजी यानी पासकी का इस्तेमाल बढ़ेगा, हालांकि इसके साथ-साथ पासवर्ड भी इस्तेमाल किए जा सकेंगे."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"चुनें कि अपनी <xliff:g id="CREATETYPES">%1$s</xliff:g> कहां सेव करनी हैं"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"अपनी जानकारी सेव करने के लिए, पासवर्ड मैनेजर चुनें और अगली बार ज़्यादा तेज़ी से साइन इन करें"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"क्या आपको <xliff:g id="APPNAME">%1$s</xliff:g> के लिए पासकी बनानी है?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"क्या आपको <xliff:g id="APPNAME">%1$s</xliff:g> के लिए पासवर्ड सेव करना है?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"क्या आपको <xliff:g id="APPNAME">%1$s</xliff:g> के लिए साइन-इन की जानकारी सेव करनी है?"</string>
     <string name="passkey" msgid="632353688396759522">"पासकी"</string>
     <string name="password" msgid="6738570945182936667">"पासवर्ड"</string>
diff --git a/packages/CredentialManager/res/values-hr/strings.xml b/packages/CredentialManager/res/values-hr/strings.xml
index 525ade3..eceb1b5 100644
--- a/packages/CredentialManager/res/values-hr/strings.xml
+++ b/packages/CredentialManager/res/values-hr/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Kako idemo u smjeru budućnosti bez zaporki, one će i dalje biti dostupne uz pristupne ključeve."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Odaberite gdje će se spremati <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Odaberite upravitelja zaporki kako biste spremili svoje informacije i drugi se put brže prijavili"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Želite li izraditi pristupni ključ za <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Spremiti zaporku za <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Spremiti informacije o prijavi za <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"pristupni ključ"</string>
     <string name="password" msgid="6738570945182936667">"zaporka"</string>
diff --git a/packages/CredentialManager/res/values-hu/strings.xml b/packages/CredentialManager/res/values-hu/strings.xml
index 1a67ecb..3415eea 100644
--- a/packages/CredentialManager/res/values-hu/strings.xml
+++ b/packages/CredentialManager/res/values-hu/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Miközben a jelszó nélküli jövő felé haladunk, a jelszavak továbbra is rendelkezésre állnak majd az azonosítókulcsok mellett."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Válassza ki, hogy hova szeretné menteni <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Válasszon jelszókezelőt, hogy menthesse az adatait, és gyorsabban jelentkezhessen be a következő alkalommal."</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Létrehoz azonosítókulcsot a következőhöz: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Szeretné elmenteni a(z) <xliff:g id="APPNAME">%1$s</xliff:g> jelszavát?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Menti a bejelentkezési adatokat a következőhöz: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"azonosítókulcs"</string>
     <string name="password" msgid="6738570945182936667">"jelszó"</string>
diff --git a/packages/CredentialManager/res/values-hy/strings.xml b/packages/CredentialManager/res/values-hy/strings.xml
index aeb3990..af803b4 100644
--- a/packages/CredentialManager/res/values-hy/strings.xml
+++ b/packages/CredentialManager/res/values-hy/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Թեև մենք առանց գաղտնաբառերի ապագայի ճանապարհին ենք, դրանք դեռ հասանելի կլինեն անցաբառերի հետ մեկտեղ։"</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Նշեք, թե որտեղ եք ուզում պահել ձեր <xliff:g id="CREATETYPES">%1$s</xliff:g>ը"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Ընտրեք գաղտնաբառերի կառավարիչ՝ ձեր տեղեկությունները պահելու և հաջորդ անգամ ավելի արագ մուտք գործելու համար"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Ստեղծե՞լ անցաբառ <xliff:g id="APPNAME">%1$s</xliff:g> հավելվածի համար"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Պահե՞լ «<xliff:g id="APPNAME">%1$s</xliff:g>» հավելվածի գաղտնաբառը"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Պահե՞լ «<xliff:g id="APPNAME">%1$s</xliff:g>» հավելվածի մուտքի տվյալները"</string>
     <string name="passkey" msgid="632353688396759522">"անցաբառ"</string>
     <string name="password" msgid="6738570945182936667">"գաղտնաբառ"</string>
diff --git a/packages/CredentialManager/res/values-in/strings.xml b/packages/CredentialManager/res/values-in/strings.xml
index 8bc8686..180c869 100644
--- a/packages/CredentialManager/res/values-in/strings.xml
+++ b/packages/CredentialManager/res/values-in/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Sandi akan tetap tersedia bersama kunci sandi seiring perjalanan menuju era di mana sandi tidak diperlukan lagi."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Pilih tempat penyimpanan <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Pilih pengelola sandi untuk menyimpan info Anda dan login lebih cepat lain kali"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Buat kunci sandi untuk <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Simpan sandi untuk <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Simpan info login untuk <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"kunci sandi"</string>
     <string name="password" msgid="6738570945182936667">"sandi"</string>
diff --git a/packages/CredentialManager/res/values-is/strings.xml b/packages/CredentialManager/res/values-is/strings.xml
index e757463..332d15e 100644
--- a/packages/CredentialManager/res/values-is/strings.xml
+++ b/packages/CredentialManager/res/values-is/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Við stefnum að framtíð án aðgangsorða en aðgangsorð verða áfram í boði samhliða aðgangslyklum."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Veldu hvar þú vilt vista <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Veldu aðgangsorðastjórnun til að vista upplýsingarnar og vera fljótari að skrá þig inn næst"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Viltu búa til aðgangslykil fyrir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Viltu vista aðgangsorð fyrir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Viltu vista innskráningarupplýsingar fyrir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"aðgangslykill"</string>
     <string name="password" msgid="6738570945182936667">"aðgangsorð"</string>
diff --git a/packages/CredentialManager/res/values-it/strings.xml b/packages/CredentialManager/res/values-it/strings.xml
index 724137b..5c83336 100644
--- a/packages/CredentialManager/res/values-it/strings.xml
+++ b/packages/CredentialManager/res/values-it/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Il futuro sarà senza password, ma per ora saranno ancora disponibili insieme alle passkey."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Scegli dove salvare le <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Seleziona un gestore delle password per salvare i tuoi dati e accedere più velocemente la prossima volta"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Vuoi creare una passkey per <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Vuoi salvare la password di <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vuoi salvare i dati di accesso di <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"passkey"</string>
     <string name="password" msgid="6738570945182936667">"password"</string>
diff --git a/packages/CredentialManager/res/values-iw/strings.xml b/packages/CredentialManager/res/values-iw/strings.xml
index a3adedf..55fb9f2 100644
--- a/packages/CredentialManager/res/values-iw/strings.xml
+++ b/packages/CredentialManager/res/values-iw/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"אנחנו מתקדמים לעבר עתיד ללא סיסמאות, אבל עדיין אפשר יהיה להשתמש בסיסמאות וגם במפתחות גישה."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"בחירת המקום לשמירה של <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"אפשר לבחור באחד משירותי ניהול הסיסמאות כדי לשמור את הפרטים ולהיכנס לחשבון מהר יותר בפעם הבאה"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"ליצור מפתח גישה ל-<xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"לשמור את הסיסמה של <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"לשמור את פרטי הכניסה של <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"מפתח גישה"</string>
     <string name="password" msgid="6738570945182936667">"סיסמה"</string>
diff --git a/packages/CredentialManager/res/values-ja/strings.xml b/packages/CredentialManager/res/values-ja/strings.xml
index 2269f7e..1ffc7db 100644
--- a/packages/CredentialManager/res/values-ja/strings.xml
+++ b/packages/CredentialManager/res/values-ja/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"将来的にパスワードレスに移行するにあたり、パスワードもパスキーと並行して引き続きご利用いただけます。"</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g>の保存先を選択"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"パスワード マネージャーを選択して情報を保存しておくと、次回からすばやくログインできます"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> のパスキーを作成しますか?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> のパスワードを保存しますか?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> のログイン情報を保存しますか?"</string>
     <string name="passkey" msgid="632353688396759522">"パスキー"</string>
     <string name="password" msgid="6738570945182936667">"パスワード"</string>
diff --git a/packages/CredentialManager/res/values-ka/strings.xml b/packages/CredentialManager/res/values-ka/strings.xml
index f58e433..fdf0797 100644
--- a/packages/CredentialManager/res/values-ka/strings.xml
+++ b/packages/CredentialManager/res/values-ka/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"უპაროლო მომავალში პაროლები კვლავ ხელმისაწვდომი იქნება, წვდომის გასაღებებთან ერთად."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"აირჩიეთ სად შეინახოთ თქვენი <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"აირჩიეთ პაროლების მმართველი თქვენი ინფორმაციის შესანახად, რომ მომავალში უფრო სწრაფად შეხვიდეთ."</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"შექმნით წვდომის გასაღებს <xliff:g id="APPNAME">%1$s</xliff:g> აპისთვის?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"შეინახავთ <xliff:g id="APPNAME">%1$s</xliff:g> აპის პაროლს?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"შეინახავთ <xliff:g id="APPNAME">%1$s</xliff:g> აპში შესვლის ინფორმაციას?"</string>
     <string name="passkey" msgid="632353688396759522">"წვდომის გასაღები"</string>
     <string name="password" msgid="6738570945182936667">"პაროლი"</string>
diff --git a/packages/CredentialManager/res/values-kk/strings.xml b/packages/CredentialManager/res/values-kk/strings.xml
index 79fe5ce..1c1b186 100644
--- a/packages/CredentialManager/res/values-kk/strings.xml
+++ b/packages/CredentialManager/res/values-kk/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Құпия сөзсіз болашақ жақын болғанына қарамастан, келешекте құпия сөздерді кіру кілттерімен қатар қолдана беруге болады."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> қайда сақталатынын таңдаңыз"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Мәліметіңізді сақтап, келесіде жылдам кіру үшін құпия сөз менеджерін таңдаңыз."</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> үшін кіру кілтін жасау керек пе?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> үшін құпия сөзді сақтау керек пе?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> үшін кіру мәліметін сақтау керек пе?"</string>
     <string name="passkey" msgid="632353688396759522">"Кіру кілті"</string>
     <string name="password" msgid="6738570945182936667">"құпия сөз"</string>
diff --git a/packages/CredentialManager/res/values-km/strings.xml b/packages/CredentialManager/res/values-km/strings.xml
index feba45e..0840879 100644
--- a/packages/CredentialManager/res/values-km/strings.xml
+++ b/packages/CredentialManager/res/values-km/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"នៅពេលដែលយើងឈានទៅរកអនាគតដែលគ្មានពាក្យសម្ងាត់ ពាក្យសម្ងាត់នៅតែអាចប្រើបានរួមជាមួយកូដសម្ងាត់។"</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"ជ្រើសរើសកន្លែង​ដែលត្រូវរក្សាទុក<xliff:g id="CREATETYPES">%1$s</xliff:g>របស់អ្នក"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"ជ្រើសរើស​កម្មវិធីគ្រប់គ្រងពាក្យសម្ងាត់ ដើម្បីរក្សាទុក​ព័ត៌មានរបស់អ្នក និងចូលគណនី​បានកាន់តែរហ័ស​នៅពេលលើកក្រោយ"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"បង្កើត​កូដសម្ងាត់​សម្រាប់ <xliff:g id="APPNAME">%1$s</xliff:g> ឬ?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"រក្សាទុក​ពាក្យសម្ងាត់​សម្រាប់ <xliff:g id="APPNAME">%1$s</xliff:g> ឬ?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"រក្សាទុក​ព័ត៌មានអំពី​ការចូលគណនីសម្រាប់ <xliff:g id="APPNAME">%1$s</xliff:g> ឬ?"</string>
     <string name="passkey" msgid="632353688396759522">"កូដសម្ងាត់"</string>
     <string name="password" msgid="6738570945182936667">"ពាក្យសម្ងាត់"</string>
diff --git a/packages/CredentialManager/res/values-kn/strings.xml b/packages/CredentialManager/res/values-kn/strings.xml
index 17d4950..84549d1 100644
--- a/packages/CredentialManager/res/values-kn/strings.xml
+++ b/packages/CredentialManager/res/values-kn/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"ನಾವು ಪಾಸ್‌ವರ್ಡ್ ರಹಿತ ತಂತ್ರಜ್ಞಾನದ ಕಡೆಗೆ ಸಾಗುತ್ತಿರುವಾಗ, ಪಾಸ್‌ಕೀಗಳ ಜೊತೆಗೆ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು ಇನ್ನೂ ಲಭ್ಯವಿರುತ್ತವೆ."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"ನಿಮ್ಮ <xliff:g id="CREATETYPES">%1$s</xliff:g> ಎಲ್ಲಿ ಸೇವ್‌ ಆಗಬೇಕು ಎಂಬುದನ್ನು ಆರಿಸಿ"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"ನಿಮ್ಮ ಮಾಹಿತಿಯನ್ನು ಉಳಿಸಲು ಪಾಸ್‌ವರ್ಡ್ ನಿರ್ವಾಹಕವನ್ನು ಆಯ್ಕೆಮಾಡಿ ಹಾಗೂ ಮುಂದಿನ ಬಾರಿ ವೇಗವಾಗಿ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> ಗಾಗಿ ಪಾಸ್‌ಕೀ ಅನ್ನು ರಚಿಸುವುದೇ?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> ಗಾಗಿ ಪಾಸ್‌ವರ್ಡ್‌ ಉಳಿಸುವುದೇ?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> ಗಾಗಿ ಸೈನ್-ಇನ್ ಮಾಹಿತಿಯನ್ನು ಉಳಿಸುವುದೇ?"</string>
     <string name="passkey" msgid="632353688396759522">"ಪಾಸ್‌ಕೀ"</string>
     <string name="password" msgid="6738570945182936667">"ಪಾಸ್‌ವರ್ಡ್"</string>
diff --git a/packages/CredentialManager/res/values-ko/strings.xml b/packages/CredentialManager/res/values-ko/strings.xml
index c6bec2e..0c970dd 100644
--- a/packages/CredentialManager/res/values-ko/strings.xml
+++ b/packages/CredentialManager/res/values-ko/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"비밀번호 없는 미래로 나아가는 과정에서 비밀번호는 여전히 패스키와 함께 사용될 것입니다."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> 저장 위치 선택"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"정보를 저장해서 다음에 더 빠르게 로그인하려면 비밀번호 관리자를 선택하세요."</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g>의 패스키를 만드시겠습니까?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g>의 비밀번호를 저장하시겠습니까?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g>의 로그인 정보를 저장하시겠습니까?"</string>
     <string name="passkey" msgid="632353688396759522">"패스키"</string>
     <string name="password" msgid="6738570945182936667">"비밀번호"</string>
diff --git a/packages/CredentialManager/res/values-ky/strings.xml b/packages/CredentialManager/res/values-ky/strings.xml
index effa375..3937ff5 100644
--- a/packages/CredentialManager/res/values-ky/strings.xml
+++ b/packages/CredentialManager/res/values-ky/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Сырсөзсүз келечекти көздөй баратсак да, аларды киргизүүчү ачкычтар менен бирге колдоно берүүгө болот."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> кайда сакталарын тандаңыз"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Маалыматыңызды сактоо жана кийинки жолу тезирээк кирүү үчүн сырсөздөрдү башкаргычты тандаңыз"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> колдонмосуна киргизүүчү ачкыч түзөсүзбү?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> үчүн сырсөз сакталсынбы?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> үчүн кирүү маалыматы сакталсынбы?"</string>
     <string name="passkey" msgid="632353688396759522">"киргизүүчү ачкыч"</string>
     <string name="password" msgid="6738570945182936667">"сырсөз"</string>
diff --git a/packages/CredentialManager/res/values-lo/strings.xml b/packages/CredentialManager/res/values-lo/strings.xml
index d921f56..79a31e8 100644
--- a/packages/CredentialManager/res/values-lo/strings.xml
+++ b/packages/CredentialManager/res/values-lo/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"ໃນຂະນະທີ່ພວກເຮົາກ້າວໄປສູ່ອະນາຄົດທີ່ບໍ່ຕ້ອງໃຊ້ລະຫັດຜ່ານ, ລະຫັດຜ່ານຈະຍັງຄົງໃຊ້ໄດ້ຄວບຄູ່ໄປກັບກະແຈຜ່ານ."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"ເລືອກບ່ອນທີ່ຈະບັນທຶກ <xliff:g id="CREATETYPES">%1$s</xliff:g> ຂອງທ່ານ"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"ເລືອກຕົວຈັດການລະຫັດຜ່ານເພື່ອບັນທຶກຂໍ້ມູນຂອງທ່ານ ແລະ ເຂົ້າສູ່ລະບົບໄວຂຶ້ນໃນເທື່ອຕໍ່ໄປ"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"ສ້າງກະແຈຜ່ານສຳລັບ <xliff:g id="APPNAME">%1$s</xliff:g> ບໍ?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"ບັນທຶກລະຫັດຜ່ານສຳລັບ <xliff:g id="APPNAME">%1$s</xliff:g> ບໍ?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"ບັນທຶກຂໍ້ມູນການເຂົ້າສູ່ລະບົບສຳລັບ <xliff:g id="APPNAME">%1$s</xliff:g> ບໍ?"</string>
     <string name="passkey" msgid="632353688396759522">"ກະແຈຜ່ານ"</string>
     <string name="password" msgid="6738570945182936667">"ລະຫັດຜ່ານ"</string>
diff --git a/packages/CredentialManager/res/values-lt/strings.xml b/packages/CredentialManager/res/values-lt/strings.xml
index f4fc6d45..e6bcd06 100644
--- a/packages/CredentialManager/res/values-lt/strings.xml
+++ b/packages/CredentialManager/res/values-lt/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Kol stengiamės padaryti, kad ateityje nereikėtų naudoti slaptažodžių, jie vis dar bus pasiekiami kartu su prieigos raktais."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Pasirinkite, kur išsaugoti „<xliff:g id="CREATETYPES">%1$s</xliff:g>“"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Pasirinkite slaptažodžių tvarkyklę, kurią naudodami galėsite išsaugoti informaciją ir kitą kartą prisijungti greičiau"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Sukurti „passkey“, skirtą „<xliff:g id="APPNAME">%1$s</xliff:g>“?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Išsaugoti „<xliff:g id="APPNAME">%1$s</xliff:g>“ slaptažodį?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Išsaugoti prisijungimo prie „<xliff:g id="APPNAME">%1$s</xliff:g>“ informaciją?"</string>
     <string name="passkey" msgid="632353688396759522">"„passkey“"</string>
     <string name="password" msgid="6738570945182936667">"slaptažodis"</string>
diff --git a/packages/CredentialManager/res/values-lv/strings.xml b/packages/CredentialManager/res/values-lv/strings.xml
index e43b5a0..a62bf28 100644
--- a/packages/CredentialManager/res/values-lv/strings.xml
+++ b/packages/CredentialManager/res/values-lv/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Lai arī pamazām notiek pāreja uz darbu bez parolēm, tās joprojām būs pieejamas līdzās piekļuves atslēgām."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Izvēlieties, kur saglabāt savas <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Lai saglabātu informāciju un nākamreiz varētu pierakstīties ātrāk, atlasiet paroļu pārvaldnieku."</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Vai izveidot piekļuves atslēgu lietotnei <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Vai saglabāt paroli lietotnei <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vai saglabāt pierakstīšanās informāciju lietotnei <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"piekļuves atslēga"</string>
     <string name="password" msgid="6738570945182936667">"parole"</string>
diff --git a/packages/CredentialManager/res/values-mk/strings.xml b/packages/CredentialManager/res/values-mk/strings.xml
index 3206640..b5d5996 100644
--- a/packages/CredentialManager/res/values-mk/strings.xml
+++ b/packages/CredentialManager/res/values-mk/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Како што се движиме кон иднина без лозинки, лозинките сепак ќе бидат достапни покрај криптографските клучеви."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Изберете каде да ги зачувате вашите <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Изберете управник со лозинки за да ги зачувате вашите податоци и да се најавите побрзо следниот пат"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Да се создаде криптографски клуч за <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Дали да се зачува лозинката за <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Да се зачуваат податоците за најавување за <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"криптографски клуч"</string>
     <string name="password" msgid="6738570945182936667">"лозинка"</string>
diff --git a/packages/CredentialManager/res/values-ml/strings.xml b/packages/CredentialManager/res/values-ml/strings.xml
index 60d0af2..fcbd12b 100644
--- a/packages/CredentialManager/res/values-ml/strings.xml
+++ b/packages/CredentialManager/res/values-ml/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"നമ്മൾ പാസ്‍വേഡ് രഹിത ഭാവിയിലേക്ക് ചുവടുവെച്ചുകൊണ്ടിരിക്കുകയാണ് എങ്കിലും, പാസ്‌കീകൾക്കൊപ്പം പാസ്‍വേഡുകൾ തുടർന്നും ലഭ്യമായിരിക്കും."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"നിങ്ങളുടെ <xliff:g id="CREATETYPES">%1$s</xliff:g> എവിടെയാണ് സംരക്ഷിക്കേണ്ടതെന്ന് തിരഞ്ഞെടുക്കുക"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"നിങ്ങളുടെ വിവരങ്ങൾ സംരക്ഷിക്കാനും അടുത്ത തവണ വേഗത്തിൽ സൈൻ ഇൻ ചെയ്യാനും ഒരു പാസ്‌വേഡ് മാനേജർ തിരഞ്ഞെടുക്കുക"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> എന്നതിനായി പാസ്‌കീ സൃഷ്ടിക്കണോ?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> എന്നതിനായി പാസ്‌വേഡ് സംരക്ഷിക്കണോ?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> എന്നതിനായി സൈൻ ഇൻ വിവരങ്ങൾ സംരക്ഷിക്കണോ?"</string>
     <string name="passkey" msgid="632353688396759522">"പാസ്‌കീ"</string>
     <string name="password" msgid="6738570945182936667">"പാസ്‌വേഡ്"</string>
diff --git a/packages/CredentialManager/res/values-mn/strings.xml b/packages/CredentialManager/res/values-mn/strings.xml
index 1050fc7..b0d4ca6b 100644
--- a/packages/CredentialManager/res/values-mn/strings.xml
+++ b/packages/CredentialManager/res/values-mn/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Бид нууц үггүй ирээдүй рүү урагшлахын хэрээр нууц үг нь нэвтрэх түлхүүрийн хамтаар боломжтой хэвээр байх болно."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g>-г хаана хадгалахаа сонгоно уу"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Мэдээллээ хадгалж, дараагийн удаа илүү хурдан нэвтрэхийн тулд нууц үгний менежерийг сонгоно уу"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g>-д passkey үүсгэх үү?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g>-н нууц үгийг хадгалах уу?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g>-н нэвтрэх мэдээллийг хадгалах уу?"</string>
     <string name="passkey" msgid="632353688396759522">"passkey"</string>
     <string name="password" msgid="6738570945182936667">"нууц үг"</string>
diff --git a/packages/CredentialManager/res/values-mr/strings.xml b/packages/CredentialManager/res/values-mr/strings.xml
index 11fee3b..5747afd 100644
--- a/packages/CredentialManager/res/values-mr/strings.xml
+++ b/packages/CredentialManager/res/values-mr/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"पासवर्ड न वापरणाऱ्या भविष्यात पुढे जाताना, पासवर्ड तरीही पासकीच्या बरोबरीने उपलब्ध असतील."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"तुमची <xliff:g id="CREATETYPES">%1$s</xliff:g> कुठे सेव्ह करायची ते निवडा"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"तुमची माहिती सेव्ह करण्यासाठी आणि पुढच्या वेळी जलद साइन इन करण्याकरिता Password Manager निवडा"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> साठी पासकी तयार करायची का?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> साठी पासवर्ड सेव्ह करायचा का?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> साठी साइन-इन माहिती सेव्ह करायची का?"</string>
     <string name="passkey" msgid="632353688396759522">"पासकी"</string>
     <string name="password" msgid="6738570945182936667">"पासवर्ड"</string>
diff --git a/packages/CredentialManager/res/values-ms/strings.xml b/packages/CredentialManager/res/values-ms/strings.xml
index 8198707..a6bc11d 100644
--- a/packages/CredentialManager/res/values-ms/strings.xml
+++ b/packages/CredentialManager/res/values-ms/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Meskipun masa depan kita nanti tidak memerlukan kata laluan, kata laluan masih akan tersedia bersama dengan kunci laluan."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Pilih tempat untuk menyimpan <xliff:g id="CREATETYPES">%1$s</xliff:g> anda"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Pilih Password Manager untuk menyimpan maklumat anda dan log masuk lebih pantas pada kali seterusnya"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Cipta kunci laluan untuk <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Simpan kata laluan untuk <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Simpan maklumat log masuk untuk <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"kunci laluan"</string>
     <string name="password" msgid="6738570945182936667">"kata laluan"</string>
diff --git a/packages/CredentialManager/res/values-my/strings.xml b/packages/CredentialManager/res/values-my/strings.xml
index 02b80cf..55eed78 100644
--- a/packages/CredentialManager/res/values-my/strings.xml
+++ b/packages/CredentialManager/res/values-my/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"စကားဝှက်မသုံးခြင်း အနာဂတ်ဆီသို့ ရှေ့ဆက်ရာတွင် လျှို့ဝှက်ကီးများနှင့်အတူ စကားဝှက်များကို ဆက်လက်အသုံးပြုနိုင်ပါမည်။"</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"သင်၏ <xliff:g id="CREATETYPES">%1$s</xliff:g> သိမ်းရန်နေရာ ရွေးခြင်း"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"သင့်အချက်အလက်သိမ်းပြီး နောက်တစ်ကြိမ်၌ ပိုမိုမြန်ဆန်စွာ လက်မှတ်ထိုးဝင်ရန် စကားဝှက်မန်နေဂျာကို ရွေးပါ"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> အတွက် လျှို့ဝှက်ကီးပြုလုပ်မလား။"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> အတွက် စကားဝှက်ကို သိမ်းမလား။"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> အတွက် လက်မှတ်ထိုးဝင်သည့်အချက်အလက်ကို သိမ်းမလား။"</string>
     <string name="passkey" msgid="632353688396759522">"လျှို့ဝှက်ကီး"</string>
     <string name="password" msgid="6738570945182936667">"စကားဝှက်"</string>
diff --git a/packages/CredentialManager/res/values-nb/strings.xml b/packages/CredentialManager/res/values-nb/strings.xml
index 4ec8524..f7c5762 100644
--- a/packages/CredentialManager/res/values-nb/strings.xml
+++ b/packages/CredentialManager/res/values-nb/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Vi går mot en fremtid uten passord, men passord fortsetter å være tilgjengelige ved siden av passnøkler."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Velg hvor du vil lagre <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Velg et verktøy for passordlagring for å lagre informasjonen din og logge på raskere neste gang"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Vil du opprette en passnøkkel for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Vil du lagre passord for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vil du lagre påloggingsinformasjon for <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"passnøkkel"</string>
     <string name="password" msgid="6738570945182936667">"passord"</string>
diff --git a/packages/CredentialManager/res/values-ne/strings.xml b/packages/CredentialManager/res/values-ne/strings.xml
index 28223dd..bc3fc0e 100644
--- a/packages/CredentialManager/res/values-ne/strings.xml
+++ b/packages/CredentialManager/res/values-ne/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"हामी पासवर्डरहित भविष्यतर्फ बढ्दै गर्दा पासकीका साथसाथै पासवर्ड पनि उपलब्ध हुने छ।"</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"तपाईं आफ्ना <xliff:g id="CREATETYPES">%1$s</xliff:g> कहाँ सेभ गर्न चाहनुहुन्छ भन्ने कुरा छनौट गर्नुहोस्"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"कुनै पासवर्ड म्यानेजरमा आफ्नो जानकारी सेभ गरी अर्को पटक अझ छिटो साइन इन गर्नुहोस्"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> को पासकी बनाउने हो?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> को पासवर्ड सेभ गर्ने हो?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> मा साइन गर्न प्रयोग गरिनु पर्ने जानकारी सेभ गर्ने हो?"</string>
     <string name="passkey" msgid="632353688396759522">"पासकी"</string>
     <string name="password" msgid="6738570945182936667">"पासवर्ड"</string>
diff --git a/packages/CredentialManager/res/values-nl/strings.xml b/packages/CredentialManager/res/values-nl/strings.xml
index b82382c..d4ce16b 100644
--- a/packages/CredentialManager/res/values-nl/strings.xml
+++ b/packages/CredentialManager/res/values-nl/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"We zijn op weg naar een wachtwoordloze toekomst, maar naast toegangssleutels kun je nog steeds gebruikmaken van wachtwoorden."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Kiezen waar je je <xliff:g id="CREATETYPES">%1$s</xliff:g> wilt opslaan"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Selecteer een wachtwoordmanager om je informatie op te slaan en de volgende keer sneller in te loggen"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Toegangssleutel maken voor <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Wachtwoord opslaan voor <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Inloggegevens opslaan voor <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"Toegangssleutel"</string>
     <string name="password" msgid="6738570945182936667">"wachtwoord"</string>
diff --git a/packages/CredentialManager/res/values-or/strings.xml b/packages/CredentialManager/res/values-or/strings.xml
index 57853f0..4ca9c39 100644
--- a/packages/CredentialManager/res/values-or/strings.xml
+++ b/packages/CredentialManager/res/values-or/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"ଆମେ ଏକ ପାସୱାର୍ଡବିହୀନ ଭବିଷ୍ୟତ ଆଡ଼କୁ ମୁଭ କରୁଥିବା ଯୋଗୁଁ ଏବେ ବି ପାସକୀଗୁଡ଼ିକ ସହିତ ପାସୱାର୍ଡ ଉପଲବ୍ଧ ହେବ।"</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"ଆପଣଙ୍କ <xliff:g id="CREATETYPES">%1$s</xliff:g> କେଉଁଠାରେ ସେଭ କରିବେ ତାହା ବାଛନ୍ତୁ"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"ଆପଣଙ୍କ ସୂଚନା ସେଭ କରି ପରବର୍ତ୍ତୀ ସମୟରେ ଶୀଘ୍ର ସାଇନ ଇନ କରିବା ପାଇଁ ଏକ Password Manager ଚୟନ କରନ୍ତୁ"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> ପାଇଁ ପାସକୀ ତିଆରି କରିବେ?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> ପାଇଁ ପାସୱାର୍ଡ ସେଭ କରିବେ?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> ପାଇଁ ସାଇନ-ଇନର ସୂଚନା ସେଭ କରିବେ?"</string>
     <string name="passkey" msgid="632353688396759522">"ପାସକୀ"</string>
     <string name="password" msgid="6738570945182936667">"ପାସୱାର୍ଡ"</string>
diff --git a/packages/CredentialManager/res/values-pa/strings.xml b/packages/CredentialManager/res/values-pa/strings.xml
index 25e1f0a..414a4ce 100644
--- a/packages/CredentialManager/res/values-pa/strings.xml
+++ b/packages/CredentialManager/res/values-pa/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"ਹਾਲਾਂਕਿ, ਅਸੀਂ ਪਾਸਵਰਡ ਰਹਿਤ ਭਵਿੱਖ ਵੱਲ ਵਧ ਰਹੇ ਹਾਂ, ਪਰ ਪਾਸਕੀਆਂ ਦੇ ਨਾਲ ਪਾਸਵਰਡ ਹਾਲੇ ਵੀ ਉਪਲਬਧ ਹੋਣਗੇ।"</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"ਚੁਣੋ ਕਿ ਆਪਣੀਆਂ <xliff:g id="CREATETYPES">%1$s</xliff:g> ਨੂੰ ਕਿੱਥੇ ਰੱਖਿਅਤ ਕਰਨਾ ਹੈ"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"ਆਪਣੀ ਜਾਣਕਾਰੀ ਨੂੰ ਰੱਖਿਅਤ ਕਰਨ ਅਤੇ ਅਗਲੀ ਵਾਰ ਤੇਜ਼ੀ ਨਾਲ ਸਾਈਨ-ਇਨ ਕਰਨ ਲਈ ਪਾਸਵਰਡ ਪ੍ਰਬੰਧਕ ਚੁਣੋ"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"ਕੀ <xliff:g id="APPNAME">%1$s</xliff:g> ਲਈ ਪਾਸਕੀ ਬਣਾਉਣੀ ਹੈ?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"ਕੀ <xliff:g id="APPNAME">%1$s</xliff:g> ਲਈ ਪਾਸਵਰਡ ਰੱਖਿਅਤ ਕਰਨਾ ਹੈ?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"ਕੀ <xliff:g id="APPNAME">%1$s</xliff:g> ਲਈ ਸਾਈਨ-ਇਨ ਜਾਣਕਾਰੀ ਰੱਖਿਅਤ ਕਰਨੀ ਹੈ?"</string>
     <string name="passkey" msgid="632353688396759522">"ਪਾਸਕੀ"</string>
     <string name="password" msgid="6738570945182936667">"ਪਾਸਵਰਡ"</string>
diff --git a/packages/CredentialManager/res/values-pl/strings.xml b/packages/CredentialManager/res/values-pl/strings.xml
index e581ff2..91e2276 100644
--- a/packages/CredentialManager/res/values-pl/strings.xml
+++ b/packages/CredentialManager/res/values-pl/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"W czasie przechodzenia na technologie niewymagające haseł możliwość stosowania haseł – niezależnie od kluczy dostępu – wciąż będzie dostępna."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Wybierz, gdzie zapisywać <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Wybierz menedżera haseł, aby zapisywać informacje i logować się szybciej"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Utworzyć klucz dla aplikacji <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Zapisać hasło do aplikacji <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Zapisać dane logowania do aplikacji <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"klucz"</string>
     <string name="password" msgid="6738570945182936667">"hasło"</string>
diff --git a/packages/CredentialManager/res/values-pt-rBR/strings.xml b/packages/CredentialManager/res/values-pt-rBR/strings.xml
index f6d03df..105441f 100644
--- a/packages/CredentialManager/res/values-pt-rBR/strings.xml
+++ b/packages/CredentialManager/res/values-pt-rBR/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Estamos avançando em direção a um futuro sem senhas, mas elas ainda vão estar disponíveis junto às chaves de acesso."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Escolha onde salvar suas <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Selecione um gerenciador de senhas para salvar suas informações e fazer login mais rapidamente na próxima vez"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Criar uma chave de acesso para o app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Salvar senha do app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Salvar informações de login do app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"chave de acesso"</string>
     <string name="password" msgid="6738570945182936667">"senha"</string>
diff --git a/packages/CredentialManager/res/values-pt-rPT/strings.xml b/packages/CredentialManager/res/values-pt-rPT/strings.xml
index 0007fad..f7259d8 100644
--- a/packages/CredentialManager/res/values-pt-rPT/strings.xml
+++ b/packages/CredentialManager/res/values-pt-rPT/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"À medida que avançamos para um futuro sem palavras-passe, as palavras-passe continuam disponíveis juntamente com as chaves de acesso."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Escolha onde guardar as suas <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Selecione um gestor de palavras-passe para guardar as suas informações e iniciar sessão mais rapidamente da próxima vez"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Criar uma chave de acesso para a app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Guardar a palavra-passe da app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Guardar as informações de início de sessão da app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"chave de acesso"</string>
     <string name="password" msgid="6738570945182936667">"palavra-passe"</string>
diff --git a/packages/CredentialManager/res/values-pt/strings.xml b/packages/CredentialManager/res/values-pt/strings.xml
index f6d03df..105441f 100644
--- a/packages/CredentialManager/res/values-pt/strings.xml
+++ b/packages/CredentialManager/res/values-pt/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Estamos avançando em direção a um futuro sem senhas, mas elas ainda vão estar disponíveis junto às chaves de acesso."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Escolha onde salvar suas <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Selecione um gerenciador de senhas para salvar suas informações e fazer login mais rapidamente na próxima vez"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Criar uma chave de acesso para o app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Salvar senha do app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Salvar informações de login do app <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"chave de acesso"</string>
     <string name="password" msgid="6738570945182936667">"senha"</string>
diff --git a/packages/CredentialManager/res/values-ro/strings.xml b/packages/CredentialManager/res/values-ro/strings.xml
index 32d0056..cfe61a9 100644
--- a/packages/CredentialManager/res/values-ro/strings.xml
+++ b/packages/CredentialManager/res/values-ro/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Ne îndreptăm spre un viitor fără parole, însă acestea sunt încă disponibile, alături de cheile de acces."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Alege unde dorești să salvezi <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Selectează un manager de parole pentru a salva informațiile și a te conecta mai rapid data viitoare"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Creezi o cheie de acces pentru <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Salvezi parola pentru <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Salvezi informațiile de conectare pentru <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"cheia de acces"</string>
     <string name="password" msgid="6738570945182936667">"parolă"</string>
diff --git a/packages/CredentialManager/res/values-ru/strings.xml b/packages/CredentialManager/res/values-ru/strings.xml
index a48b0f2c..ba7d34a 100644
--- a/packages/CredentialManager/res/values-ru/strings.xml
+++ b/packages/CredentialManager/res/values-ru/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Хотя движение к будущему без паролей уже началось, их по-прежнему можно будет использовать наряду с ключами доступа."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Укажите, куда нужно сохранить <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Выберите менеджер паролей, чтобы сохранять учетные данные и быстро выполнять вход."</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Создать ключ доступа для приложения \"<xliff:g id="APPNAME">%1$s</xliff:g>\"?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Сохранить пароль для приложения \"<xliff:g id="APPNAME">%1$s</xliff:g>\"?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Сохранить учетные данные для приложения \"<xliff:g id="APPNAME">%1$s</xliff:g>\"?"</string>
     <string name="passkey" msgid="632353688396759522">"ключ доступа"</string>
     <string name="password" msgid="6738570945182936667">"пароль"</string>
diff --git a/packages/CredentialManager/res/values-si/strings.xml b/packages/CredentialManager/res/values-si/strings.xml
index d6113b3..03ada97 100644
--- a/packages/CredentialManager/res/values-si/strings.xml
+++ b/packages/CredentialManager/res/values-si/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"අපි මුරපද රහිත අනාගතයක් කරා ගමන් කරන විට, මුරයතුරු සමග මුරපද තවමත් පවතී."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"ඔබේ <xliff:g id="CREATETYPES">%1$s</xliff:g> සුරැකිය යුතු ස්ථානය තෝරා ගන්න"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"ඔබේ තතු සුරැකීමට සහ මීළඟ වතාවේ වේගයෙන් පුරනය වීමට මුරපද කළමනාකරුවෙකු තෝරන්න"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> සඳහා මුරයතුර තනන්න ද?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> සඳහා මුරපදය සුරකින්න ද?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> සඳහා පුරනය වීමේ තතු සුරකින්න ද?"</string>
     <string name="passkey" msgid="632353688396759522">"මුරයතුර"</string>
     <string name="password" msgid="6738570945182936667">"මුරපදය"</string>
diff --git a/packages/CredentialManager/res/values-sk/strings.xml b/packages/CredentialManager/res/values-sk/strings.xml
index 62d8f19..7198625 100644
--- a/packages/CredentialManager/res/values-sk/strings.xml
+++ b/packages/CredentialManager/res/values-sk/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Blížime sa k budúcnosti bez hesiel, ale heslá budú popri prístupových kľúčoch stále k dispozícii."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Vyberte, kam sa majú ukladať <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Vyberte správcu hesiel, do ktorého sa budú ukladať vaše údaje, aby ste sa nabudúce mohli rýchlejšie prihlásiť"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Chcete vytvoriť prístupový kľúč pre aplikáciu <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Chcete uložiť heslo pre aplikáciu <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Chcete uložiť prihlasovacie údaje pre aplikáciu <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"prístupový kľúč"</string>
     <string name="password" msgid="6738570945182936667">"heslo"</string>
diff --git a/packages/CredentialManager/res/values-sl/strings.xml b/packages/CredentialManager/res/values-sl/strings.xml
index 846d27d..3ff85f0 100644
--- a/packages/CredentialManager/res/values-sl/strings.xml
+++ b/packages/CredentialManager/res/values-sl/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Na poti v prihodnost brez gesel bodo poleg ključev za dostop še vedno v uporabi tudi gesla."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Izbira mesta za shranjevanje <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Izberite upravitelja gesel za shranjevanje podatkov za prijavo, da se boste naslednjič lahko hitreje prijavili."</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Želite ustvariti ključ za dostop do aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Želite shraniti geslo za aplikacijo <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Želite shraniti podatke za prijavo za aplikacijo <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"ključ za dostop"</string>
     <string name="password" msgid="6738570945182936667">"geslo"</string>
diff --git a/packages/CredentialManager/res/values-sq/strings.xml b/packages/CredentialManager/res/values-sq/strings.xml
index 7678125..41f6391 100644
--- a/packages/CredentialManager/res/values-sq/strings.xml
+++ b/packages/CredentialManager/res/values-sq/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Teksa shkojmë drejt një të ardhmeje pa fjalëkalime, këto të fundit do të ofrohen ende së bashku me çelësat e kalimit."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Zgjidh se ku t\'i ruash <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Zgjidh një menaxher fjalëkalimesh për të ruajtur informacionet e tua dhe për t\'u identifikuar më shpejt herën tjetër"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Të krijohet çelësi i kalimit për <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Të ruhet fjalëkalimi për <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Të ruhen informacionet e identifikimit për <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"çelësin e kalimit"</string>
     <string name="password" msgid="6738570945182936667">"fjalëkalimi"</string>
diff --git a/packages/CredentialManager/res/values-sr/strings.xml b/packages/CredentialManager/res/values-sr/strings.xml
index 8c71e71..1a5567f 100644
--- a/packages/CredentialManager/res/values-sr/strings.xml
+++ b/packages/CredentialManager/res/values-sr/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Како се крећемо ка будућности без лозинки, лозинке ће и даље бити доступне уз приступне кодове."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Одаберите где ћете сачувати: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Изаберите менаџера лозинки да бисте сачували податке и брже се пријавили следећи пут"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Желите да направите приступни кôд за: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Желите да сачувате лозинку за: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Желите да сачувате податке за пријављивање за: <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"приступни кôд"</string>
     <string name="password" msgid="6738570945182936667">"лозинка"</string>
diff --git a/packages/CredentialManager/res/values-sv/strings.xml b/packages/CredentialManager/res/values-sv/strings.xml
index 9aa1165..8937b01 100644
--- a/packages/CredentialManager/res/values-sv/strings.xml
+++ b/packages/CredentialManager/res/values-sv/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Medan vi beger oss mot en lösenordslös framtid kommer lösenord fortfarande att vara tillgängliga utöver nycklar."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Välj var du vill spara <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Välj en lösenordshanterare för att spara dina uppgifter och logga in snabbare nästa gång"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Vill du skapa en nyckel för <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Vill du spara lösenordet för <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Vill du spara inloggningsuppgifterna för <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"nyckel"</string>
     <string name="password" msgid="6738570945182936667">"lösenord"</string>
diff --git a/packages/CredentialManager/res/values-sw/strings.xml b/packages/CredentialManager/res/values-sw/strings.xml
index adf659e..051122f 100644
--- a/packages/CredentialManager/res/values-sw/strings.xml
+++ b/packages/CredentialManager/res/values-sw/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Tunavyoelekea katika enzi isiyo ya manenosiri, manenosiri yataendelea kupatikana pamoja na funguo za siri."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Chagua ambako unahifadhi <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Chagua kidhibiti cha manenosiri ili uhifadhi taarifa zako na uingie kwenye akaunti kwa urahisi wakati mwingine"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Ungependa kuunda ufunguo wa siri kwa ajili ya <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Ungependa kuhifadhi nenosiri kwa ajili ya <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Ungependa kuhifadhi maelezo ya kuingia katika akaunti kwa ajili ya <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"ufunguo wa siri"</string>
     <string name="password" msgid="6738570945182936667">"nenosiri"</string>
diff --git a/packages/CredentialManager/res/values-ta/strings.xml b/packages/CredentialManager/res/values-ta/strings.xml
index c43776e..64d4a24 100644
--- a/packages/CredentialManager/res/values-ta/strings.xml
+++ b/packages/CredentialManager/res/values-ta/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"கடவுச்சொல்லற்ற எதிர்காலத்தை நோக்கி நாம் பயணிக்கிறோம். கடவுச்சாவிகளைப் பயன்படுத்தும் இதே வேளையில் கடவுச்சொற்களையும் பயன்படுத்த முடியும்."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"உங்கள் <xliff:g id="CREATETYPES">%1$s</xliff:g> எங்கே சேமிக்கப்பட வேண்டும் என்பதைத் தேர்வுசெய்யுங்கள்"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"உங்கள் தகவல்களைச் சேமித்து அடுத்த முறை விரைவாக உள்நுழைய ஒரு கடவுச்சொல் நிர்வாகியைத் தேர்வுசெய்யுங்கள்"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> ஆப்ஸுக்கான கடவுச்சாவியை உருவாக்கவா?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> ஆப்ஸுக்கான கடவுச்சொல்லைச் சேமிக்கவா?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> ஆப்ஸுக்கான உள்நுழைவு விவரங்களைச் சேமிக்கவா?"</string>
     <string name="passkey" msgid="632353688396759522">"கடவுச்சாவி"</string>
     <string name="password" msgid="6738570945182936667">"கடவுச்சொல்"</string>
diff --git a/packages/CredentialManager/res/values-te/strings.xml b/packages/CredentialManager/res/values-te/strings.xml
index 980fb152..066f785 100644
--- a/packages/CredentialManager/res/values-te/strings.xml
+++ b/packages/CredentialManager/res/values-te/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"మనం భవిష్యత్తులో పాస్‌వర్డ్ రహిత టెక్నాలజీని ఉపయోగించినా, పాస్‌కీలతో పాటు పాస్‌వర్డ్‌లు కూడా అందుబాటులో ఉంటాయి."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"మీ <xliff:g id="CREATETYPES">%1$s</xliff:g> ఎక్కడ సేవ్ చేయాలో ఎంచుకోండి"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"తర్వాతిసారి మరింత వేగంగా సైన్ ఇన్ చేసేందుకు వీలుగా మీ సమాచారాన్ని సేవ్ చేయడం కోసం ఒక పాస్‌వర్డ్ మేనేజర్‌ను ఎంచుకోండి"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> కోసం పాస్‌-కీని క్రియేట్ చేయాలా?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> కోసం పాస్‌వర్డ్‌ను సేవ్ చేయాలా?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> కోసం సైన్ ఇన్ సమాచారాన్ని సేవ్ చేయాలా?"</string>
     <string name="passkey" msgid="632353688396759522">"పాస్-కీ"</string>
     <string name="password" msgid="6738570945182936667">"పాస్‌వర్డ్"</string>
diff --git a/packages/CredentialManager/res/values-th/strings.xml b/packages/CredentialManager/res/values-th/strings.xml
index e222d6b..783d057 100644
--- a/packages/CredentialManager/res/values-th/strings.xml
+++ b/packages/CredentialManager/res/values-th/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"ในขณะที่เราก้าวไปสู่อนาคตที่ไม่ต้องใช้รหัสผ่านนั้น รหัสผ่านจะยังคงใช้ได้อยู่ควบคู่ไปกับการเปลี่ยนไปใช้พาสคีย์"</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"เลือกว่าต้องการบันทึก<xliff:g id="CREATETYPES">%1$s</xliff:g>ไว้ที่ใด"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"เลือกเครื่องมือจัดการรหัสผ่านเพื่อบันทึกข้อมูลและลงชื่อเข้าใช้เร็วขึ้นในครั้งถัดไป"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"สร้างพาสคีย์สำหรับ <xliff:g id="APPNAME">%1$s</xliff:g> ไหม"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"บันทึกรหัสผ่านสำหรับ <xliff:g id="APPNAME">%1$s</xliff:g> ไหม"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"บันทึกข้อมูลการลงชื่อเข้าใช้สำหรับ <xliff:g id="APPNAME">%1$s</xliff:g> ไหม"</string>
     <string name="passkey" msgid="632353688396759522">"พาสคีย์"</string>
     <string name="password" msgid="6738570945182936667">"รหัสผ่าน"</string>
diff --git a/packages/CredentialManager/res/values-tl/strings.xml b/packages/CredentialManager/res/values-tl/strings.xml
index 5487df1..18283ea 100644
--- a/packages/CredentialManager/res/values-tl/strings.xml
+++ b/packages/CredentialManager/res/values-tl/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Habang lumalayo tayo sa mga password, magiging available pa rin ang mga password kasama ng mga passkey."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Piliin kung saan mo ise-save ang iyong <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Pumili ng password manager para ma-save ang iyong impormasyon at makapag-sign in nang mas mabilis sa susunod na pagkakataon"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Gumawa ng passkey para sa <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"I-save ang password para sa <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"I-save ang impormasyon sa pag-sign in para sa <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"passkey"</string>
     <string name="password" msgid="6738570945182936667">"password"</string>
diff --git a/packages/CredentialManager/res/values-tr/strings.xml b/packages/CredentialManager/res/values-tr/strings.xml
index 5dda8aa..8778797 100644
--- a/packages/CredentialManager/res/values-tr/strings.xml
+++ b/packages/CredentialManager/res/values-tr/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Şifresiz bir geleceğe doğru ilerlerken şifreler, geçiş anahtarlarıyla birlikte kullanılmaya devam edecektir."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"<xliff:g id="CREATETYPES">%1$s</xliff:g> kaydedileceği yeri seçin"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Bilgilerinizi kaydedip bir dahaki sefere daha hızlı oturum açmak için bir şifre yöneticisi seçin"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> için geçiş anahtarı oluşturulsun mu?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> için şifre kaydedilsin mi?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> için oturum açma bilgileri kaydedilsin mi?"</string>
     <string name="passkey" msgid="632353688396759522">"Geçiş anahtarı"</string>
     <string name="password" msgid="6738570945182936667">"Şifre"</string>
diff --git a/packages/CredentialManager/res/values-uk/strings.xml b/packages/CredentialManager/res/values-uk/strings.xml
index 1cda5d4..53de1b3 100644
--- a/packages/CredentialManager/res/values-uk/strings.xml
+++ b/packages/CredentialManager/res/values-uk/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"На шляху до безпарольного майбутнього паролі й надалі будуть використовуватися паралельно з ключами доступу."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Виберіть, де зберігати <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Виберіть менеджер паролів, щоб зберігати свої дані й надалі входити в облікові записи швидше"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Створити ключ доступу для додатка <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Зберегти пароль для додатка <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Зберегти дані для входу для додатка <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"ключ доступу"</string>
     <string name="password" msgid="6738570945182936667">"пароль"</string>
diff --git a/packages/CredentialManager/res/values-ur/strings.xml b/packages/CredentialManager/res/values-ur/strings.xml
index 105045c..47e33fb 100644
--- a/packages/CredentialManager/res/values-ur/strings.xml
+++ b/packages/CredentialManager/res/values-ur/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"چونکہ ہم بغیر پاس ورڈ والے مستقبل کی طرف جا رہے ہیں اس کے باوجود پاس ورڈز پاس کیز کے ساتھ ہی دستیاب ہوں گے۔"</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"منتخب کریں کہ آپ کی <xliff:g id="CREATETYPES">%1$s</xliff:g> کو کہاں محفوظ کرنا ہے"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"اپنی معلومات کو محفوظ کرنے اور اگلی بار تیزی سے سائن ان کرنے کے لیے پاس ورڈ مینیجر منتخب کریں"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> کے لیے پاس کی تخلیق کریں؟"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> کے لیے پاس ورڈ کو محفوظ کریں؟"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> کے لیے سائن ان کی معلومات محفوظ کریں؟"</string>
     <string name="passkey" msgid="632353688396759522">"پاس کی"</string>
     <string name="password" msgid="6738570945182936667">"پاس ورڈ"</string>
diff --git a/packages/CredentialManager/res/values-uz/strings.xml b/packages/CredentialManager/res/values-uz/strings.xml
index ec42f07..6025cae0 100644
--- a/packages/CredentialManager/res/values-uz/strings.xml
+++ b/packages/CredentialManager/res/values-uz/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Parolsiz kelajak sari harakatlanar ekanmiz, parollar kalitlar bilan birga ishlatilishda davom etadi."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Bu <xliff:g id="CREATETYPES">%1$s</xliff:g> qayerga saqlanishini tanlang"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Maʼlumotlaringizni saqlash va keyingi safar tez kirish uchun parollar menejerini tanlang"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"<xliff:g id="APPNAME">%1$s</xliff:g> uchun kod yaratilsinmi?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"<xliff:g id="APPNAME">%1$s</xliff:g> uchun parol saqlansinmi?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"<xliff:g id="APPNAME">%1$s</xliff:g> uchun kirish maʼlumoti saqlansinmi?"</string>
     <string name="passkey" msgid="632353688396759522">"kalit"</string>
     <string name="password" msgid="6738570945182936667">"parol"</string>
diff --git a/packages/CredentialManager/res/values-vi/strings.xml b/packages/CredentialManager/res/values-vi/strings.xml
index dbee658..1411036 100644
--- a/packages/CredentialManager/res/values-vi/strings.xml
+++ b/packages/CredentialManager/res/values-vi/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Trong quá trình chúng tôi hướng đến tương lai không dùng mật khẩu, bạn vẫn sẽ dùng được mật khẩu cùng với khoá truy cập."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Chọn vị trí lưu <xliff:g id="CREATETYPES">%1$s</xliff:g> của bạn"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Hãy chọn một trình quản lý mật khẩu để lưu thông tin của bạn và đăng nhập nhanh hơn vào lần tới"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Tạo khoá đăng nhập cho <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Lưu mật khẩu cho <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Lưu thông tin đăng nhập cho <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"khoá đăng nhập"</string>
     <string name="password" msgid="6738570945182936667">"mật khẩu"</string>
diff --git a/packages/CredentialManager/res/values-zh-rCN/strings.xml b/packages/CredentialManager/res/values-zh-rCN/strings.xml
index c82f2f8..dcc2269 100644
--- a/packages/CredentialManager/res/values-zh-rCN/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rCN/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"在我们向无密码未来迈进的过程中,密码仍会与通行密钥并行使用。"</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"选择保存<xliff:g id="CREATETYPES">%1$s</xliff:g>的位置"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"请选择一款密码管理工具来保存您的信息,以便下次更快地登录"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"要为“<xliff:g id="APPNAME">%1$s</xliff:g>”创建通行密钥吗?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"要保存“<xliff:g id="APPNAME">%1$s</xliff:g>”的密码吗?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"要保存“<xliff:g id="APPNAME">%1$s</xliff:g>”的登录信息吗?"</string>
     <string name="passkey" msgid="632353688396759522">"通行密钥"</string>
     <string name="password" msgid="6738570945182936667">"密码"</string>
diff --git a/packages/CredentialManager/res/values-zh-rHK/strings.xml b/packages/CredentialManager/res/values-zh-rHK/strings.xml
index 1d3e5aa..5e893f6 100644
--- a/packages/CredentialManager/res/values-zh-rHK/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rHK/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"我們將會改用無密碼技術,而密碼仍可與密鑰並行使用。"</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"選擇儲存<xliff:g id="CREATETYPES">%1$s</xliff:g>的位置"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"選取密碼管理工具即可儲存自己的資料,縮短下次登入的時間"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"要為「<xliff:g id="APPNAME">%1$s</xliff:g>」建立密鑰嗎?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"要儲存「<xliff:g id="APPNAME">%1$s</xliff:g>」的密碼嗎?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"要儲存「<xliff:g id="APPNAME">%1$s</xliff:g>」的登入資料嗎?"</string>
     <string name="passkey" msgid="632353688396759522">"密鑰"</string>
     <string name="password" msgid="6738570945182936667">"密碼"</string>
diff --git a/packages/CredentialManager/res/values-zh-rTW/strings.xml b/packages/CredentialManager/res/values-zh-rTW/strings.xml
index 184505a..1e1dca4 100644
--- a/packages/CredentialManager/res/values-zh-rTW/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rTW/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"我們日後將改採無密碼技術,密碼仍可與密碼金鑰並行使用。"</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"選擇要將<xliff:g id="CREATETYPES">%1$s</xliff:g>存在哪裡"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"選取密碼管理工具並儲存資訊,下次就能更快登入"</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"要為「<xliff:g id="APPNAME">%1$s</xliff:g>」建立密碼金鑰嗎?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"要儲存「<xliff:g id="APPNAME">%1$s</xliff:g>」的密碼嗎?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"要儲存「<xliff:g id="APPNAME">%1$s</xliff:g>」的登入資訊嗎?"</string>
     <string name="passkey" msgid="632353688396759522">"密碼金鑰"</string>
     <string name="password" msgid="6738570945182936667">"密碼"</string>
diff --git a/packages/CredentialManager/res/values-zu/strings.xml b/packages/CredentialManager/res/values-zu/strings.xml
index 8feeb17..72a1e8f 100644
--- a/packages/CredentialManager/res/values-zu/strings.xml
+++ b/packages/CredentialManager/res/values-zu/strings.xml
@@ -39,8 +39,10 @@
     <string name="seamless_transition_detail" msgid="4475509237171739843">"Njengoba sibhekela kwikusasa elingenaphasiwedi, amagama ayimfihlo asazotholakala eceleni kokhiye bokudlula."</string>
     <string name="choose_provider_title" msgid="8870795677024868108">"Khetha lapho ongagcina khona i-<xliff:g id="CREATETYPES">%1$s</xliff:g> yakho"</string>
     <string name="choose_provider_body" msgid="4967074531845147434">"Khetha isiphathi sephasiwedi ukuze ulondoloze ulwazi lwakho futhi ungene ngemvume ngokushesha ngesikhathi esizayo."</string>
-    <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Sungula ukhiye wokudlula we-<xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
-    <string name="choose_create_option_password_title" msgid="7097275038523578687">"Londolozela amaphasiwedi ye-<xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for choose_create_option_passkey_title (7980430650778623135) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (6238446571944651980) -->
+    <skip />
     <string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Londoloza ulwazi lokungena lwe-<xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
     <string name="passkey" msgid="632353688396759522">"ukhiye wokudlula"</string>
     <string name="password" msgid="6738570945182936667">"iphasiwedi"</string>
diff --git a/packages/CredentialManager/res/values/dimens.xml b/packages/CredentialManager/res/values/dimens.xml
index 350920b2..82dee5c 100644
--- a/packages/CredentialManager/res/values/dimens.xml
+++ b/packages/CredentialManager/res/values/dimens.xml
@@ -26,7 +26,7 @@
     <dimen name="autofill_dropdown_textview_min_width">112dp</dimen>
     <dimen name="autofill_dropdown_textview_max_width">230dp</dimen>
     <dimen name="dropdown_layout_horizontal_margin">24dp</dimen>
-    <integer name="autofill_max_visible_datasets">5</integer>
+    <integer name="autofill_max_visible_datasets">4</integer>
     <dimen name="dropdown_touch_target_min_height">48dp</dimen>
     <dimen name="horizontal_chip_padding">8dp</dimen>
     <dimen name="vertical_chip_padding">6dp</dimen>
diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml
index 82b47a9..527701c 100644
--- a/packages/CredentialManager/res/values/strings.xml
+++ b/packages/CredentialManager/res/values/strings.xml
@@ -63,9 +63,9 @@
   <!-- This appears as the description body of the modal bottom sheet which provides all available providers for users to choose. [CHAR LIMIT=200] -->
   <string name="choose_provider_body">Select a password manager to save your info and sign in faster next time</string>
   <!-- This appears as the title of the modal bottom sheet for users to choose the create option inside a provider when the credential type is passkey. [CHAR LIMIT=200] -->
-  <string name="choose_create_option_passkey_title">Create passkey for <xliff:g id="appName" example="Tribank">%1$s</xliff:g>?</string>
+  <string name="choose_create_option_passkey_title">Create passkey to sign in to <xliff:g id="appName" example="Tribank">%1$s</xliff:g>?</string>
   <!-- This appears as the title of the modal bottom sheet for users to choose the create option inside a provider when the credential type is password. [CHAR LIMIT=200] -->
-  <string name="choose_create_option_password_title">Save password for <xliff:g id="appName" example="Tribank">%1$s</xliff:g>?</string>
+  <string name="choose_create_option_password_title">Save password to sign in to <xliff:g id="appName" example="Tribank">%1$s</xliff:g>?</string>
   <!-- This appears as the title of the modal bottom sheet for users to choose the create option inside a provider when the credential type is others. [CHAR LIMIT=200] -->
   <string name="choose_create_option_sign_in_title">Save sign-in info for <xliff:g id="appName" example="Tribank">%1$s</xliff:g>?</string>
   <!-- Types which are inserted as a placeholder as credentialTypes for other strings. [CHAR LIMIT=200] -->
diff --git a/packages/CredentialManager/shared/Android.bp b/packages/CredentialManager/shared/Android.bp
index 47ca944..f8ee96e 100644
--- a/packages/CredentialManager/shared/Android.bp
+++ b/packages/CredentialManager/shared/Android.bp
@@ -11,6 +11,7 @@
     name: "CredentialManagerShared",
     manifest: "AndroidManifest.xml",
     srcs: ["src/**/*.kt"],
+    resource_dirs: ["res"],
     static_libs: [
         "androidx.activity_activity-compose",
         "androidx.core_core-ktx",
diff --git a/packages/CredentialManager/shared/res/drawable/ic_passkey_24.xml b/packages/CredentialManager/shared/res/drawable/ic_passkey_24.xml
new file mode 100644
index 0000000..b81f7c5
--- /dev/null
+++ b/packages/CredentialManager/shared/res/drawable/ic_passkey_24.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<!--LINT.IfChange-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="960"
+        android:viewportHeight="960">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M120,800L120,688Q120,654 137.5,625.5Q155,597 184,582Q246,551 310,535.5Q374,520 440,520Q460,520 480,521.5Q500,523 520,526Q516,584 541,635.5Q566,687 614,720L614,800L120,800ZM760,920L700,860L700,674Q656,661 628,624.5Q600,588 600,540Q600,482 641,441Q682,400 740,400Q798,400 839,441Q880,482 880,540Q880,585 854.5,620Q829,655 790,670L840,720L780,780L840,840L760,920ZM440,480Q374,480 327,433Q280,386 280,320Q280,254 327,207Q374,160 440,160Q506,160 553,207Q600,254 600,320Q600,386 553,433Q506,480 440,480ZM740,560Q757,560 768.5,548.5Q780,537 780,520Q780,503 768.5,491.5Q757,480 740,480Q723,480 711.5,491.5Q700,503 700,520Q700,537 711.5,548.5Q723,560 740,560Z"/>
+</vector>
+<!--LINT.ThenChange(/packages/CredentialManager/res/drawable/ic_passkey_24.xml)-->
\ No newline at end of file
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
index a5f227a..892eabf 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
@@ -30,6 +30,7 @@
 import android.text.TextUtils
 import android.util.Log
 import androidx.activity.result.IntentSenderRequest
+import androidx.credentials.PasswordCredential
 import androidx.credentials.PublicKeyCredential
 import androidx.credentials.provider.Action
 import androidx.credentials.provider.AuthenticationAction
@@ -39,6 +40,7 @@
 import androidx.credentials.provider.PublicKeyCredentialEntry
 import androidx.credentials.provider.RemoteEntry
 import com.android.credentialmanager.IS_AUTO_SELECTED_KEY
+import com.android.credentialmanager.R
 import com.android.credentialmanager.model.get.ActionEntryInfo
 import com.android.credentialmanager.model.get.AuthenticationEntryInfo
 import com.android.credentialmanager.model.get.CredentialEntryInfo
@@ -46,8 +48,9 @@
 import com.android.credentialmanager.model.get.ProviderInfo
 import com.android.credentialmanager.model.get.RemoteEntryInfo
 import com.android.credentialmanager.TAG
+import com.android.credentialmanager.model.EntryInfo
 
-fun CredentialEntryInfo.getIntentSenderRequest(
+fun EntryInfo.getIntentSenderRequest(
     isAutoSelected: Boolean = false
 ): IntentSenderRequest? {
     val entryIntent = fillInIntent?.putExtra(IS_AUTO_SELECTED_KEY, isAutoSelected)
@@ -123,14 +126,19 @@
                     pendingIntent = credentialEntry.pendingIntent,
                     fillInIntent = it.frameworkExtrasIntent,
                     credentialType = CredentialType.PASSWORD,
+                    rawCredentialType = PasswordCredential.TYPE_PASSWORD_CREDENTIAL,
                     credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(),
                     userName = credentialEntry.username.toString(),
                     displayName = credentialEntry.displayName?.toString(),
                     icon = credentialEntry.icon.loadDrawable(context),
-                    shouldTintIcon = credentialEntry.isDefaultIcon,
+                    shouldTintIcon = credentialEntry.hasDefaultIcon,
                     lastUsedTimeMillis = credentialEntry.lastUsedTime,
                     isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
-                            credentialEntry.autoSelectAllowedFromOption,
+                            credentialEntry.isAutoSelectAllowedFromOption,
+                    entryGroupId = credentialEntry.entryGroupId.toString(),
+                    isDefaultIconPreferredAsSingleProvider =
+                            credentialEntry.isDefaultIconPreferredAsSingleProvider,
+                    affiliatedDomain = credentialEntry.affiliatedDomain?.toString(),
                 )
                 )
             }
@@ -144,14 +152,21 @@
                     pendingIntent = credentialEntry.pendingIntent,
                     fillInIntent = it.frameworkExtrasIntent,
                     credentialType = CredentialType.PASSKEY,
+                    rawCredentialType = PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
                     credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(),
                     userName = credentialEntry.username.toString(),
                     displayName = credentialEntry.displayName?.toString(),
-                    icon = credentialEntry.icon.loadDrawable(context),
-                    shouldTintIcon = credentialEntry.isDefaultIcon,
+                    icon = if (credentialEntry.hasDefaultIcon)
+                        context.getDrawable(R.drawable.ic_passkey_24)
+                    else credentialEntry.icon.loadDrawable(context),
+                    shouldTintIcon = credentialEntry.hasDefaultIcon,
                     lastUsedTimeMillis = credentialEntry.lastUsedTime,
                     isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
-                            credentialEntry.autoSelectAllowedFromOption,
+                            credentialEntry.isAutoSelectAllowedFromOption,
+                    entryGroupId = credentialEntry.entryGroupId.toString(),
+                    isDefaultIconPreferredAsSingleProvider =
+                            credentialEntry.isDefaultIconPreferredAsSingleProvider,
+                    affiliatedDomain = credentialEntry.affiliatedDomain?.toString(),
                 )
                 )
             }
@@ -165,15 +180,20 @@
                     pendingIntent = credentialEntry.pendingIntent,
                     fillInIntent = it.frameworkExtrasIntent,
                     credentialType = CredentialType.UNKNOWN,
+                    rawCredentialType = credentialEntry.type,
                     credentialTypeDisplayName =
                     credentialEntry.typeDisplayName?.toString().orEmpty(),
                     userName = credentialEntry.title.toString(),
                     displayName = credentialEntry.subtitle?.toString(),
                     icon = credentialEntry.icon.loadDrawable(context),
-                    shouldTintIcon = credentialEntry.isDefaultIcon,
+                    shouldTintIcon = credentialEntry.hasDefaultIcon,
                     lastUsedTimeMillis = credentialEntry.lastUsedTime,
                     isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
-                            credentialEntry.autoSelectAllowedFromOption,
+                            credentialEntry.isAutoSelectAllowedFromOption,
+                    entryGroupId = credentialEntry.entryGroupId.toString(),
+                    isDefaultIconPreferredAsSingleProvider =
+                            credentialEntry.isDefaultIconPreferredAsSingleProvider,
+                    affiliatedDomain = credentialEntry.affiliatedDomain?.toString(),
                 )
                 )
             }
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/CredentialEntryInfo.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/CredentialEntryInfo.kt
index 9725881..a657e97 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/CredentialEntryInfo.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/get/CredentialEntryInfo.kt
@@ -31,6 +31,11 @@
     fillInIntent: Intent?,
     /** Type of this credential used for sorting. Not localized so must not be directly displayed. */
     val credentialType: CredentialType,
+    /**
+     * String type value of this credential used for sorting. Not localized so must not be directly
+     * displayed.
+     */
+    val rawCredentialType: String,
     /** Localized type value of this credential used for display purpose. */
     val credentialTypeDisplayName: String,
     val providerDisplayName: String,
@@ -40,6 +45,10 @@
     val shouldTintIcon: Boolean,
     val lastUsedTimeMillis: Instant?,
     val isAutoSelectable: Boolean,
+    val entryGroupId: String, // Used for deduplication, and displayed as the grouping title
+                              // "For <value-of-entryGroupId>" on the more-option screen.
+    val isDefaultIconPreferredAsSingleProvider: Boolean,
+    val affiliatedDomain: String?,
 ) : EntryInfo(
     providerId,
     entryKey,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index 5830b9f..6a1998a 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -20,6 +20,7 @@
 import android.content.Context
 import android.content.pm.PackageInfo
 import android.content.pm.PackageManager
+import android.credentials.GetCredentialRequest
 import android.credentials.selection.CreateCredentialProviderData
 import android.credentials.selection.DisabledProviderData
 import android.credentials.selection.Entry
@@ -44,6 +45,9 @@
 import androidx.credentials.CreateCustomCredentialRequest
 import androidx.credentials.CreatePasswordRequest
 import androidx.credentials.CreatePublicKeyCredentialRequest
+import androidx.credentials.PasswordCredential
+import androidx.credentials.PriorityHints
+import androidx.credentials.PublicKeyCredential
 import androidx.credentials.provider.CreateEntry
 import androidx.credentials.provider.RemoteEntry
 import org.json.JSONObject
@@ -162,6 +166,25 @@
 /** Utility functions for converting CredentialManager data structures to or from UI formats. */
 class GetFlowUtils {
     companion object {
+        fun extractTypePriorityMap(request: GetCredentialRequest): Map<String, Int> {
+            val typePriorityMap = mutableMapOf<String, Int>()
+            request.credentialOptions.forEach {option ->
+                // TODO(b/280085288) - use jetpack conversion method when exposed, rather than
+                // parsing from the raw Bundle
+                val priority = option.candidateQueryData.getInt(
+                        "androidx.credentials.BUNDLE_KEY_TYPE_PRIORITY_VALUE",
+                        when (option.type) {
+                            PasswordCredential.TYPE_PASSWORD_CREDENTIAL ->
+                                PriorityHints.PRIORITY_PASSWORD_OR_SIMILAR
+                            PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL -> 100
+                            else -> PriorityHints.PRIORITY_DEFAULT
+                        }
+                )
+                typePriorityMap[option.type] = priority
+            }
+            return typePriorityMap
+        }
+
         // Returns the list (potentially empty) of enabled provider.
         fun toProviderList(
             providerDataList: List<GetCredentialProviderData>,
@@ -193,6 +216,9 @@
                         null
                     }
                 }
+
+            val typePriorityMap = extractTypePriorityMap(getCredentialRequest)
+
             return com.android.credentialmanager.getflow.RequestDisplayInfo(
                 appName = originName?.ifEmpty { null }
                     ?: getAppLabel(context.packageManager, requestInfo.packageName)
@@ -203,6 +229,7 @@
                     // exposed.
                     "androidx.credentials.BUNDLE_KEY_PREFER_IDENTITY_DOC_UI"),
                 preferTopBrandingContent = preferTopBrandingContent,
+                typePriorityMap = typePriorityMap,
             )
         }
     }
@@ -282,6 +309,8 @@
             val appPreferredDefaultProviderId: String? =
                 if (!requestInfo.hasPermissionToOverrideDefault()) null
                 else createCredentialRequestJetpack?.displayInfo?.preferDefaultProvider
+            val typeDisplayIcon = createCredentialRequestJetpack?.displayInfo?.credentialTypeIcon
+                    ?.loadDrawable(context)
             return when (createCredentialRequestJetpack) {
                 is CreatePasswordRequest -> RequestDisplayInfo(
                     createCredentialRequestJetpack.id,
@@ -302,7 +331,6 @@
                     newRequestDisplayInfoFromPasskeyJson(
                         requestJson = createCredentialRequestJetpack.requestJson,
                         appLabel = appLabel,
-                        context = context,
                         preferImmediatelyAvailableCredentials =
                         createCredentialRequestJetpack.preferImmediatelyAvailableCredentials,
                         appPreferredDefaultProviderId = appPreferredDefaultProviderId,
@@ -311,6 +339,7 @@
                         // the passkey type. For now, directly parse it ourselves.
                         isAutoSelectRequest = createCredentialRequest.credentialData.getBoolean(
                             Constants.BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS, false),
+                        typeIcon = context.getDrawable(R.drawable.ic_passkey_24) ?: return null,
                     )
                 }
                 is CreateCustomCredentialRequest -> {
@@ -323,7 +352,7 @@
                         subtitle = displayInfo.userDisplayName?.toString(),
                         type = CredentialType.UNKNOWN,
                         appName = appLabel,
-                        typeIcon = displayInfo.credentialTypeIcon?.loadDrawable(context)
+                        typeIcon = typeDisplayIcon
                             ?: context.getDrawable(R.drawable.ic_other_sign_in_24) ?: return null,
                         preferImmediatelyAvailableCredentials =
                         createCredentialRequestJetpack.preferImmediatelyAvailableCredentials,
@@ -502,7 +531,7 @@
         private fun newRequestDisplayInfoFromPasskeyJson(
             requestJson: String,
             appLabel: String,
-            context: Context,
+            typeIcon: Drawable,
             preferImmediatelyAvailableCredentials: Boolean,
             appPreferredDefaultProviderId: String?,
             userSetDefaultProviderIds: Set<String>,
@@ -525,7 +554,7 @@
                 displayname,
                 CredentialType.PASSKEY,
                 appLabel,
-                context.getDrawable(R.drawable.ic_passkey_24) ?: return null,
+                typeIcon,
                 preferImmediatelyAvailableCredentials,
                 appPreferredDefaultProviderId,
                 userSetDefaultProviderIds,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index 0f17217..4e1f4ee 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -33,7 +33,6 @@
 import android.os.Bundle
 import android.os.CancellationSignal
 import android.os.OutcomeReceiver
-import android.provider.Settings
 import android.service.autofill.AutofillService
 import android.service.autofill.Dataset
 import android.service.autofill.Field
@@ -140,7 +139,7 @@
             override fun onResult(result: GetCandidateCredentialsResponse) {
                 Log.i(TAG, "getCandidateCredentials onResult")
                 val fillResponse = convertToFillResponse(result, request,
-                    responseClientState)
+                    responseClientState, GetFlowUtils.extractTypePriorityMap(getCredRequest))
                 if (fillResponse != null) {
                     callback.onSuccess(fillResponse)
                 } else {
@@ -197,7 +196,8 @@
     private fun convertToFillResponse(
             getCredResponse: GetCandidateCredentialsResponse,
             filLRequest: FillRequest,
-            responseClientState: Bundle
+            responseClientState: Bundle,
+            typePriorityMap: Map<String, Int>,
     ): FillResponse? {
         val candidateProviders = getCredResponse.candidateProviderDataList
         if (candidateProviders.isEmpty()) {
@@ -213,7 +213,7 @@
         autofillIdToProvidersMap.forEach { (autofillId, providers) ->
             validFillResponse = processProvidersForAutofillId(
                     filLRequest, autofillId, providers, entryIconMap, fillResponseBuilder,
-                    getCredResponse.pendingIntent)
+                    getCredResponse.intent, typePriorityMap)
                     .or(validFillResponse)
         }
         if (!validFillResponse) {
@@ -229,7 +229,8 @@
             providerDataList: ArrayList<GetCredentialProviderData>,
             entryIconMap: Map<String, Icon>,
             fillResponseBuilder: FillResponse.Builder,
-            bottomSheetPendingIntent: PendingIntent?
+            bottomSheetIntent: Intent,
+            typePriorityMap: Map<String, Int>,
     ): Boolean {
         val providerList = GetFlowUtils.toProviderList(
             providerDataList,
@@ -237,23 +238,15 @@
         if (providerList.isEmpty()) {
             return false
         }
-        var totalEntryCount = 0
-        providerList.forEach { provider ->
-            totalEntryCount += provider.credentialEntryList.size
-        }
-        val providerDisplayInfo: ProviderDisplayInfo = toProviderDisplayInfo(providerList)
+        val providerDisplayInfo: ProviderDisplayInfo =
+                toProviderDisplayInfo(providerList, typePriorityMap)
+        var totalEntryCount = providerDisplayInfo.sortedUserNameToCredentialEntryList.size
         val inlineSuggestionsRequest = filLRequest.inlineSuggestionsRequest
-        val inlineMaxSuggestedCount = inlineSuggestionsRequest?.maxSuggestionCount ?: 0
         val inlinePresentationSpecs = inlineSuggestionsRequest?.inlinePresentationSpecs
         val inlinePresentationSpecsCount = inlinePresentationSpecs?.size ?: 0
-        val maxDropdownDisplayLimit = this.resources.getInteger(
+        val maxDatasetDisplayLimit = this.resources.getInteger(
                 com.android.credentialmanager.R.integer.autofill_max_visible_datasets)
-        var maxInlineItemCount = totalEntryCount
-        maxInlineItemCount = maxInlineItemCount.coerceAtMost(inlineMaxSuggestedCount)
-        val lastDropdownDatasetIndex = Settings.Global.getInt(this.contentResolver,
-                Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
-                (maxDropdownDisplayLimit - 1)).coerceAtMost(totalEntryCount)
-
+                .coerceAtMost(totalEntryCount)
         var i = 0
         var datasetAdded = false
 
@@ -267,6 +260,8 @@
                 }
             }
         }
+        bottomSheetIntent.putExtra(
+                ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, providerDataList)
         providerDisplayInfo.sortedUserNameToCredentialEntryList.forEach usernameLoop@{
             val primaryEntry = it.sortedCredentialEntryList.first()
             val pendingIntent = primaryEntry.pendingIntent
@@ -276,7 +271,7 @@
                 Log.e(TAG, "PendingIntent was missing from the entry.")
                 return@usernameLoop
             }
-            if (i >= maxInlineItemCount && i >= lastDropdownDatasetIndex) {
+            if (i >= maxDatasetDisplayLimit) {
                 return@usernameLoop
             }
             val icon: Icon = if (primaryEntry.icon == null) {
@@ -289,7 +284,7 @@
             }
             // Create inline presentation
             var inlinePresentation: InlinePresentation? = null
-            if (inlinePresentationSpecs != null && i < maxInlineItemCount) {
+            if (inlinePresentationSpecs != null && i < maxDatasetDisplayLimit) {
                 val spec: InlinePresentationSpec? = if (i < inlinePresentationSpecsCount) {
                     inlinePresentationSpecs[i]
                 } else {
@@ -303,7 +298,7 @@
                 }
             }
             var dropdownPresentation: RemoteViews? = null
-            if (i < lastDropdownDatasetIndex) {
+            if (i < maxDatasetDisplayLimit) {
                 dropdownPresentation = RemoteViewsFactory
                         .createDropdownPresentation(this, icon, primaryEntry)
             }
@@ -329,17 +324,15 @@
                             .build())
             datasetAdded = true
             i++
-
-            if (i == lastDropdownDatasetIndex && bottomSheetPendingIntent != null) {
-                addDropdownMoreOptionsPresentation(bottomSheetPendingIntent, autofillId,
-                        fillResponseBuilder)
-            }
         }
         val pinnedSpec = getLastInlinePresentationSpec(inlinePresentationSpecs,
                 inlinePresentationSpecsCount)
-        if (datasetAdded && bottomSheetPendingIntent != null && pinnedSpec != null) {
-            addPinnedInlineSuggestion(bottomSheetPendingIntent, pinnedSpec, autofillId,
-                    fillResponseBuilder, providerDataList)
+        if (datasetAdded) {
+            addDropdownMoreOptionsPresentation(bottomSheetIntent, autofillId, fillResponseBuilder)
+            if (pinnedSpec != null) {
+                addPinnedInlineSuggestion(pinnedSpec, autofillId,
+                        fillResponseBuilder, bottomSheetIntent)
+            }
         }
         return datasetAdded
     }
@@ -370,13 +363,14 @@
     }
 
     private fun addDropdownMoreOptionsPresentation(
-            bottomSheetPendingIntent: PendingIntent,
+            bottomSheetIntent: Intent,
             autofillId: AutofillId,
             fillResponseBuilder: FillResponse.Builder
     ) {
         val presentationBuilder = Presentations.Builder()
                 .setMenuPresentation(
                         RemoteViewsFactory.createMoreSignInOptionsPresentation(this))
+        val pendingIntent = setUpBottomSheetPendingIntent(bottomSheetIntent)
 
         fillResponseBuilder.addDataset(
                 Dataset.Builder()
@@ -385,7 +379,7 @@
                                 Field.Builder().setPresentations(
                                         presentationBuilder.build())
                                         .build())
-                        .setAuthentication(bottomSheetPendingIntent.intentSender)
+                        .setAuthentication(pendingIntent.intentSender)
                         .build()
         )
     }
@@ -401,37 +395,41 @@
     }
 
     private fun addPinnedInlineSuggestion(
-            bottomSheetPendingIntent: PendingIntent,
             spec: InlinePresentationSpec,
             autofillId: AutofillId,
             fillResponseBuilder: FillResponse.Builder,
-            providerDataList: ArrayList<GetCredentialProviderData>
+            bottomSheetIntent: Intent
     ) {
+        val pendingIntent = setUpBottomSheetPendingIntent(bottomSheetIntent)
+
         val dataSetBuilder = Dataset.Builder()
         val sliceBuilder = InlineSuggestionUi
-                .newContentBuilder(bottomSheetPendingIntent)
+                .newContentBuilder(pendingIntent)
                 .setStartIcon(Icon.createWithResource(this,
                         com.android.credentialmanager.R.drawable.more_horiz_24px))
         val presentationBuilder = Presentations.Builder()
                 .setInlinePresentation(InlinePresentation(
                         sliceBuilder.build().slice, spec, /* pinned= */ true))
 
-        val extrasIntent = Intent()
-        extrasIntent.putExtra(ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, providerDataList)
-
         fillResponseBuilder.addDataset(
                 dataSetBuilder
                         .setField(
                                 autofillId,
                                 Field.Builder().setPresentations(
-                                        presentationBuilder.build())
-                                        .build())
-                        .setAuthentication(bottomSheetPendingIntent.intentSender)
-                        .setCredentialFillInIntent(extrasIntent)
+                                        presentationBuilder.build()
+                                ).build()
+                        )
+                        .setAuthentication(pendingIntent.intentSender)
                         .build()
         )
     }
 
+    private fun setUpBottomSheetPendingIntent(intent: Intent): PendingIntent {
+        intent.setAction(java.util.UUID.randomUUID().toString())
+        return PendingIntent.getActivity(this, /*requestCode=*/0, intent,
+                PendingIntent.FLAG_MUTABLE, /*options=*/null)
+    }
+
     /**
      *  Maps Autofill Id to provider list. For example, passing in a provider info
      *
@@ -571,7 +569,7 @@
             responseClientState: Bundle
     ): GetCredentialRequest? {
         val credentialOptions: MutableList<CredentialOption> = mutableListOf()
-        traverseStructureForRequest(structure, credentialOptions, responseClientState)
+        traverseStructureForRequest(structure, credentialOptions, responseClientState, sessionId)
 
         if (credentialOptions.isNotEmpty()) {
             val dataBundle = Bundle()
@@ -587,7 +585,8 @@
     private fun traverseStructureForRequest(
             structure: AssistStructure,
             cmRequests: MutableList<CredentialOption>,
-            responseClientState: Bundle
+            responseClientState: Bundle,
+            sessionId: Int
     ) {
         val traversedViewNodes: MutableSet<AutofillId> = mutableSetOf()
         val credentialOptionsFromHints: MutableMap<String, CredentialOption> = mutableMapOf()
@@ -599,7 +598,7 @@
         windowNodes.forEach { windowNode: AssistStructure.WindowNode ->
             traverseNodeForRequest(
                 windowNode.rootViewNode, cmRequests, responseClientState, traversedViewNodes,
-                credentialOptionsFromHints)
+                credentialOptionsFromHints, sessionId)
         }
     }
 
@@ -608,11 +607,12 @@
             cmRequests: MutableList<CredentialOption>,
             responseClientState: Bundle,
             traversedViewNodes: MutableSet<AutofillId>,
-            credentialOptionsFromHints: MutableMap<String, CredentialOption>
+            credentialOptionsFromHints: MutableMap<String, CredentialOption>,
+            sessionId: Int
     ) {
         viewNode.autofillId?.let {
             cmRequests.addAll(getCredentialOptionsFromViewNode(viewNode, it, responseClientState,
-                traversedViewNodes, credentialOptionsFromHints))
+                traversedViewNodes, credentialOptionsFromHints, sessionId))
             traversedViewNodes.add(it)
         }
 
@@ -623,7 +623,7 @@
 
         children.forEach { childNode: AssistStructure.ViewNode ->
             traverseNodeForRequest(childNode, cmRequests, responseClientState, traversedViewNodes,
-                credentialOptionsFromHints)
+                credentialOptionsFromHints, sessionId)
         }
     }
 
@@ -632,7 +632,8 @@
             autofillId: AutofillId,
             responseClientState: Bundle,
             traversedViewNodes: MutableSet<AutofillId>,
-            credentialOptionsFromHints: MutableMap<String, CredentialOption>
+            credentialOptionsFromHints: MutableMap<String, CredentialOption>,
+            sessionId: Int
     ): MutableList<CredentialOption> {
         val credentialOptions: MutableList<CredentialOption> = mutableListOf()
         if (Flags.autofillCredmanDevIntegration() && viewNode.credentialManagerRequest != null) {
@@ -643,12 +644,25 @@
                         .getParcelableArrayList(
                             CredentialProviderService.EXTRA_AUTOFILL_ID, AutofillId::class.java)
                         ?.let { associatedAutofillIds ->
+                            // Set sessionId in autofillIds. The autofillIds stored in Credential
+                            // Options do not have associated session id and will result in
+                            // different hashes than the ones in assistStructure.
+                            associatedAutofillIds.forEach { associatedAutofillId ->
+                                associatedAutofillId.sessionId = sessionId
+                            }
+
                             // Check whether any of the associated autofill ids have already been
                             // traversed. If so, skip, to dedupe on duplicate credential options.
                             if ((traversedViewNodes intersect associatedAutofillIds.toSet())
                                         .isEmpty()) {
                                 credentialOptions.add(credentialOption)
                             }
+
+                            // Set the autofillIds with session id back to credential option.
+                            credentialOption.candidateQueryData.putParcelableArrayList(
+                                CredentialProviderService.EXTRA_AUTOFILL_ID,
+                                associatedAutofillIds
+                            )
                         }
             }
         }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
index d319e4c..a7b5c36 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
@@ -16,8 +16,15 @@
 
 package com.android.credentialmanager.common.ui
 
+import android.credentials.flags.Flags
+import androidx.compose.animation.animateContentSize
 import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.rememberCoroutineScope
@@ -25,6 +32,7 @@
 import androidx.compose.ui.graphics.Color
 import com.android.compose.rememberSystemUiController
 import com.android.compose.theme.LocalAndroidColorScheme
+import androidx.compose.ui.unit.dp
 import com.android.credentialmanager.common.material.ModalBottomSheetLayout
 import com.android.credentialmanager.common.material.ModalBottomSheetValue
 import com.android.credentialmanager.common.material.rememberModalBottomSheetState
@@ -34,40 +42,68 @@
 
 /** Draws a modal bottom sheet with the same styles and effects shared by various flows. */
 @Composable
+@OptIn(ExperimentalMaterial3Api::class)
 fun ModalBottomSheet(
-    sheetContent: @Composable ColumnScope.() -> Unit,
-    onDismiss: () -> Unit,
-    isInitialRender: Boolean,
-    onInitialRenderComplete: () -> Unit,
-    isAutoSelectFlow: Boolean,
+        sheetContent: @Composable () -> Unit,
+        onDismiss: () -> Unit,
+        isInitialRender: Boolean,
+        onInitialRenderComplete: () -> Unit,
+        isAutoSelectFlow: Boolean,
 ) {
-    val scope = rememberCoroutineScope()
-    val state = rememberModalBottomSheetState(
-        initialValue = if (isAutoSelectFlow) ModalBottomSheetValue.Expanded
-        else ModalBottomSheetValue.Hidden,
-        skipHalfExpanded = true
-    )
-    val sysUiController = rememberSystemUiController()
-    if (state.targetValue == ModalBottomSheetValue.Hidden || isAutoSelectFlow) {
-        setTransparentSystemBarsColor(sysUiController)
+    if (Flags.selectorUiImprovementsEnabled()) {
+        val state = androidx.compose.material3.rememberModalBottomSheetState(
+                skipPartiallyExpanded = true
+        )
+        androidx.compose.material3.ModalBottomSheet(
+                onDismissRequest = onDismiss,
+                containerColor = LocalAndroidColorScheme.current.surfaceBright,
+                sheetState = state,
+                content = {
+                    Box(
+                            modifier = Modifier
+                                    .animateContentSize()
+                                    .wrapContentHeight()
+                                    .fillMaxWidth()
+                    ) {
+                        sheetContent()
+                    }
+                },
+                scrimColor = MaterialTheme.colorScheme.scrim.copy(alpha = .32f),
+                shape = EntryShape.TopRoundedCorner,
+                dragHandle = null,
+                // Never take over the full screen. We always want to leave some top scrim space
+                // for exiting and viewing the underlying app to help a user gain context.
+                modifier = Modifier.padding(top = 56.dp),
+        )
     } else {
-        setBottomSheetSystemBarsColor(sysUiController)
-    }
-    ModalBottomSheetLayout(
-        sheetBackgroundColor = LocalAndroidColorScheme.current.surfaceBright,
-        modifier = Modifier.background(Color.Transparent),
-        sheetState = state,
-        sheetContent = sheetContent,
-        sheetShape = EntryShape.TopRoundedCorner,
-    ) {}
-    LaunchedEffect(state.currentValue, state.targetValue) {
-        if (state.currentValue == ModalBottomSheetValue.Hidden) {
-            if (isInitialRender) {
-                onInitialRenderComplete()
-                scope.launch { state.show() }
-            } else if (state.targetValue == ModalBottomSheetValue.Hidden) {
-                // Only dismiss ui when the motion is downwards
-                onDismiss()
+        val scope = rememberCoroutineScope()
+        val state = rememberModalBottomSheetState(
+                initialValue = if (isAutoSelectFlow) ModalBottomSheetValue.Expanded
+                else ModalBottomSheetValue.Hidden,
+                skipHalfExpanded = true
+        )
+        val sysUiController = rememberSystemUiController()
+        if (state.targetValue == ModalBottomSheetValue.Hidden || isAutoSelectFlow) {
+            setTransparentSystemBarsColor(sysUiController)
+        } else {
+            setBottomSheetSystemBarsColor(sysUiController)
+        }
+        ModalBottomSheetLayout(
+                sheetBackgroundColor = LocalAndroidColorScheme.current.surfaceBright,
+                modifier = Modifier.background(Color.Transparent),
+                sheetState = state,
+                sheetContent = { sheetContent() },
+                sheetShape = EntryShape.TopRoundedCorner,
+        ) {}
+        LaunchedEffect(state.currentValue, state.targetValue) {
+            if (state.currentValue == ModalBottomSheetValue.Hidden) {
+                if (isInitialRender) {
+                    onInitialRenderComplete()
+                    scope.launch { state.show() }
+                } else if (state.targetValue == ModalBottomSheetValue.Hidden) {
+                    // Only dismiss ui when the motion is downwards
+                    onDismiss()
+                }
             }
         }
     }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt
index bdfe399..c68ae8b 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt
@@ -18,7 +18,10 @@
 
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.WindowInsets
 import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.asPaddingValues
+import androidx.compose.foundation.layout.navigationBars
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.wrapContentHeight
 import androidx.compose.foundation.lazy.LazyColumn
@@ -66,6 +69,9 @@
             horizontalAlignment = Alignment.CenterHorizontally,
             content = content,
             verticalArrangement = contentVerticalArrangement,
+            // The bottom sheet overlaps with the navigation bars but make sure the actual content
+            // in the bottom sheet does not.
+            contentPadding = WindowInsets.navigationBars.asPaddingValues(),
         )
     }
 }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
index a6253b8..56bd066 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
@@ -29,13 +29,10 @@
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.ArrowBack
 import androidx.compose.material.icons.outlined.Lock
-import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.SuggestionChip
 import androidx.compose.material3.SuggestionChipDefaults
-import androidx.compose.material3.TopAppBar
-import androidx.compose.material3.TopAppBarDefaults
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -81,6 +78,8 @@
     isLockedAuthEntry: Boolean = false,
     enforceOneLine: Boolean = false,
     onTextLayout: (TextLayoutResult) -> Unit = {},
+    /** Get flow only, if present, where be drawn as a line above the headline. */
+    affiliatedDomainText: String? = null,
 ) {
     val iconPadding = Modifier.wrapContentSize().padding(
         // Horizontal padding should be 16dp, but the suggestion chip itself
@@ -105,6 +104,13 @@
             ) {
                 // Apply weight so that the trailing icon can always show.
                 Column(modifier = Modifier.wrapContentHeight().fillMaxWidth().weight(1f)) {
+                    if (!affiliatedDomainText.isNullOrBlank()) {
+                        BodySmallText(
+                            text = affiliatedDomainText,
+                            enforceOneLine = enforceOneLine,
+                            onTextLayout = onTextLayout,
+                        )
+                    }
                     SmallTitleText(
                         text = entryHeadlineText,
                         enforceOneLine = enforceOneLine,
@@ -278,31 +284,6 @@
 }
 
 /**
- * A single row of leading icon and text describing a benefit of passkeys, used by the
- * [com.android.credentialmanager.createflow.PasskeyIntroCard].
- */
-@Composable
-fun PasskeyBenefitRow(
-    leadingIconPainter: Painter,
-    text: String,
-) {
-    Row(
-        horizontalArrangement = Arrangement.spacedBy(16.dp),
-        verticalAlignment = Alignment.CenterVertically,
-        modifier = Modifier.fillMaxWidth()
-    ) {
-        Icon(
-            modifier = Modifier.size(24.dp),
-            painter = leadingIconPainter,
-            tint = LocalAndroidColorScheme.current.onSurfaceVariant,
-            // Decorative purpose only.
-            contentDescription = null,
-        )
-        BodyMediumText(text = text)
-    }
-}
-
-/**
  * A single row of one or two CTA buttons for continuing or cancelling the current step.
  */
 @Composable
@@ -327,40 +308,36 @@
     }
 }
 
-@OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun MoreOptionTopAppBar(
     text: String,
     onNavigationIconClicked: () -> Unit,
     bottomPadding: Dp,
 ) {
-    TopAppBar(
-        title = {
-            LargeTitleText(text = text, modifier = Modifier.padding(horizontal = 4.dp))
-        },
-        navigationIcon = {
-            IconButton(
+    Row(
+            modifier = Modifier.padding(top = 12.dp, bottom = bottomPadding),
+            verticalAlignment = Alignment.CenterVertically,
+    ) {
+        IconButton(
                 modifier = Modifier.padding(top = 8.dp, bottom = 8.dp, start = 4.dp).size(48.dp),
                 onClick = onNavigationIconClicked
-            ) {
-                Box(
+        ) {
+            Box(
                     modifier = Modifier.size(48.dp),
                     contentAlignment = Alignment.Center,
-                ) {
-                    Icon(
+            ) {
+                Icon(
                         imageVector = Icons.Filled.ArrowBack,
                         contentDescription = stringResource(
-                            R.string.accessibility_back_arrow_button
+                                R.string.accessibility_back_arrow_button
                         ),
                         modifier = Modifier.size(24.dp).autoMirrored(),
                         tint = LocalAndroidColorScheme.current.onSurfaceVariant,
-                    )
-                }
+                )
             }
-        },
-        colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent),
-        modifier = Modifier.padding(top = 12.dp, bottom = bottomPadding)
-    )
+        }
+        LargeTitleText(text = text, modifier = Modifier.padding(horizontal = 4.dp))
+    }
 }
 
 private fun Modifier.autoMirrored() = composed {
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
index 02afc54..7966a86 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
@@ -34,9 +34,9 @@
         private const val passwordCharacterLength = 15
 
         fun createDropdownPresentation(
-                context: Context,
-                icon: Icon,
-                credentialEntryInfo: CredentialEntryInfo
+            context: Context,
+            icon: Icon,
+            credentialEntryInfo: CredentialEntryInfo
         ): RemoteViews {
             var layoutId: Int = com.android.credentialmanager.R.layout
                     .credman_dropdown_presentation_layout
@@ -45,41 +45,37 @@
                 return remoteViews
             }
             setRemoteViewsPaddings(remoteViews, context, /* primaryTextBottomPadding=*/0)
-            if (credentialEntryInfo.credentialType == CredentialType.PASSKEY) {
-                val displayName = credentialEntryInfo.displayName ?: credentialEntryInfo.userName
-                remoteViews.setTextViewText(android.R.id.text1, displayName)
-                val secondaryText = if (credentialEntryInfo.displayName != null)
+            val displayName = credentialEntryInfo.displayName ?: credentialEntryInfo.userName
+            remoteViews.setTextViewText(android.R.id.text1, displayName)
+            val secondaryText =
+                if (credentialEntryInfo.displayName != null
+                    && (credentialEntryInfo.displayName != credentialEntryInfo.userName))
                     (credentialEntryInfo.userName + " " + bulletPoint + " "
                             + credentialEntryInfo.credentialTypeDisplayName
                             + " " + bulletPoint + " " + credentialEntryInfo.providerDisplayName)
                 else (credentialEntryInfo.credentialTypeDisplayName + " " + bulletPoint + " "
                         + credentialEntryInfo.providerDisplayName)
-                remoteViews.setTextViewText(android.R.id.text2, secondaryText)
-            } else {
-                remoteViews.setTextViewText(android.R.id.text1, credentialEntryInfo.userName)
-                remoteViews.setTextViewText(android.R.id.text2,
-                        bulletPoint.repeat(passwordCharacterLength))
-            }
+            remoteViews.setTextViewText(android.R.id.text2, secondaryText)
             val textColorPrimary = ContextCompat.getColor(context,
-                    com.android.credentialmanager.R.color.text_primary)
+                com.android.credentialmanager.R.color.text_primary)
             remoteViews.setTextColor(android.R.id.text1, textColorPrimary)
             val textColorSecondary = ContextCompat.getColor(context, com.android
                     .credentialmanager.R.color.text_secondary)
             remoteViews.setTextColor(android.R.id.text2, textColorSecondary)
             remoteViews.setImageViewIcon(android.R.id.icon1, icon);
             remoteViews.setBoolean(
-                    android.R.id.icon1, setAdjustViewBoundsMethodName, true);
+                android.R.id.icon1, setAdjustViewBoundsMethodName, true);
             remoteViews.setInt(
-                    android.R.id.icon1,
-                    setMaxHeightMethodName,
-                    context.resources.getDimensionPixelSize(
-                            com.android.credentialmanager.R.dimen.autofill_icon_size));
+                android.R.id.icon1,
+                setMaxHeightMethodName,
+                context.resources.getDimensionPixelSize(
+                    com.android.credentialmanager.R.dimen.autofill_icon_size));
             remoteViews.setContentDescription(android.R.id.icon1, credentialEntryInfo
                     .providerDisplayName);
             val drawableId =
-                    com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one
+                com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one
             remoteViews.setInt(
-                    android.R.id.content, setBackgroundResourceMethodName, drawableId);
+                android.R.id.content, setBackgroundResourceMethodName, drawableId);
             return remoteViews
         }
 
@@ -89,68 +85,68 @@
             val remoteViews = RemoteViews(context.packageName, layoutId)
             setRemoteViewsPaddings(remoteViews, context)
             remoteViews.setTextViewText(android.R.id.text1, ContextCompat.getString(context,
-                    com.android.credentialmanager
-                            .R.string.dropdown_presentation_more_sign_in_options_text))
+                com.android.credentialmanager
+                        .R.string.dropdown_presentation_more_sign_in_options_text))
 
             val textColorPrimary = ContextCompat.getColor(context,
-                    com.android.credentialmanager.R.color.text_primary)
+                com.android.credentialmanager.R.color.text_primary)
             remoteViews.setTextColor(android.R.id.text1, textColorPrimary)
             val icon = Icon.createWithResource(context, com
                     .android.credentialmanager.R.drawable.more_horiz_24px)
             icon.setTint(ContextCompat.getColor(context,
-                    com.android.credentialmanager.R.color.sign_in_options_icon_color))
+                com.android.credentialmanager.R.color.sign_in_options_icon_color))
             remoteViews.setImageViewIcon(android.R.id.icon1, icon)
             remoteViews.setBoolean(
-                    android.R.id.icon1, setAdjustViewBoundsMethodName, true);
+                android.R.id.icon1, setAdjustViewBoundsMethodName, true);
             remoteViews.setInt(
-                    android.R.id.icon1,
-                    setMaxHeightMethodName,
-                    context.resources.getDimensionPixelSize(
-                            com.android.credentialmanager.R.dimen.autofill_icon_size));
+                android.R.id.icon1,
+                setMaxHeightMethodName,
+                context.resources.getDimensionPixelSize(
+                    com.android.credentialmanager.R.dimen.autofill_icon_size));
             val drawableId =
-                    com.android.credentialmanager.R.drawable.more_options_list_item
+                com.android.credentialmanager.R.drawable.more_options_list_item
             remoteViews.setInt(
-                    android.R.id.content, setBackgroundResourceMethodName, drawableId);
+                android.R.id.content, setBackgroundResourceMethodName, drawableId);
             return remoteViews
         }
 
         private fun setRemoteViewsPaddings(
-                remoteViews: RemoteViews, context: Context) {
+            remoteViews: RemoteViews, context: Context) {
             val bottomPadding = context.resources.getDimensionPixelSize(
-                    com.android.credentialmanager.R.dimen.autofill_view_bottom_padding)
+                com.android.credentialmanager.R.dimen.autofill_view_bottom_padding)
             setRemoteViewsPaddings(remoteViews, context, bottomPadding)
         }
 
         private fun setRemoteViewsPaddings(
-                remoteViews: RemoteViews, context: Context, primaryTextBottomPadding: Int) {
+            remoteViews: RemoteViews, context: Context, primaryTextBottomPadding: Int) {
             val leftPadding = context.resources.getDimensionPixelSize(
-                    com.android.credentialmanager.R.dimen.autofill_view_left_padding)
+                com.android.credentialmanager.R.dimen.autofill_view_left_padding)
             val iconToTextPadding = context.resources.getDimensionPixelSize(
-                    com.android.credentialmanager.R.dimen.autofill_view_icon_to_text_padding)
+                com.android.credentialmanager.R.dimen.autofill_view_icon_to_text_padding)
             val rightPadding = context.resources.getDimensionPixelSize(
-                    com.android.credentialmanager.R.dimen.autofill_view_right_padding)
+                com.android.credentialmanager.R.dimen.autofill_view_right_padding)
             val topPadding = context.resources.getDimensionPixelSize(
-                    com.android.credentialmanager.R.dimen.autofill_view_top_padding)
+                com.android.credentialmanager.R.dimen.autofill_view_top_padding)
             val bottomPadding = context.resources.getDimensionPixelSize(
-                    com.android.credentialmanager.R.dimen.autofill_view_bottom_padding)
+                com.android.credentialmanager.R.dimen.autofill_view_bottom_padding)
             remoteViews.setViewPadding(
-                    android.R.id.icon1,
-                    leftPadding,
-                    /* top=*/0,
-                    /* right=*/0,
-                    /* bottom=*/0)
+                android.R.id.icon1,
+                leftPadding,
+                /* top=*/0,
+                /* right=*/0,
+                /* bottom=*/0)
             remoteViews.setViewPadding(
-                    android.R.id.text1,
-                    iconToTextPadding,
-                    /* top=*/topPadding,
-                    /* right=*/rightPadding,
-                    primaryTextBottomPadding)
+                android.R.id.text1,
+                iconToTextPadding,
+                /* top=*/topPadding,
+                /* right=*/rightPadding,
+                primaryTextBottomPadding)
             remoteViews.setViewPadding(
-                    android.R.id.text2,
-                    iconToTextPadding,
-                    /* top=*/0,
-                    /* right=*/rightPadding,
-                    /* bottom=*/bottomPadding)
+                android.R.id.text2,
+                iconToTextPadding,
+                /* top=*/0,
+                /* right=*/rightPadding,
+                /* bottom=*/bottomPadding)
         }
 
         private fun isDarkMode(context: Context): Boolean {
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index d24adb5..4ef7760 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -16,6 +16,7 @@
 
 package com.android.credentialmanager.createflow
 
+import android.credentials.flags.Flags.selectorUiImprovementsEnabled
 import android.text.TextUtils
 import androidx.activity.compose.ManagedActivityResultLauncher
 import androidx.activity.result.ActivityResult
@@ -329,6 +330,18 @@
             )
         }
         item { Divider(thickness = 24.dp, color = Color.Transparent) }
+
+        val footerDescription = createOptionInfo.footerDescription
+        if (selectorUiImprovementsEnabled()) {
+            if (!footerDescription.isNullOrBlank()) {
+                item {
+                    Row(modifier = Modifier.fillMaxWidth().wrapContentHeight()) {
+                        BodySmallText(text = footerDescription)
+                    }
+                }
+                item { Divider(thickness = 24.dp, color = Color.Transparent) }
+            }
+        }
         item {
             CredentialContainerCard {
                 PrimaryCreateOptionRow(
@@ -366,18 +379,19 @@
                 },
             )
         }
-        val footerDescription = createOptionInfo.footerDescription
-        if (footerDescription != null && footerDescription.length > 0) {
-            item {
-                Divider(
-                    thickness = 1.dp,
-                    color = LocalAndroidColorScheme.current.outlineVariant,
-                    modifier = Modifier.padding(vertical = 16.dp)
-                )
-            }
-            item {
-                Row(modifier = Modifier.fillMaxWidth().wrapContentHeight()) {
-                    BodySmallText(text = footerDescription)
+        if (!selectorUiImprovementsEnabled()) {
+            if (footerDescription != null && footerDescription.length > 0) {
+                item {
+                    Divider(
+                        thickness = 1.dp,
+                        color = LocalAndroidColorScheme.current.outlineVariant,
+                        modifier = Modifier.padding(vertical = 16.dp)
+                    )
+                }
+                item {
+                    Row(modifier = Modifier.fillMaxWidth().wrapContentHeight()) {
+                        BodySmallText(text = footerDescription)
+                    }
                 }
             }
         }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index 4ed84b9..748c798 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -16,6 +16,7 @@
 
 package com.android.credentialmanager.getflow
 
+import android.credentials.flags.Flags.selectorUiImprovementsEnabled
 import android.graphics.drawable.Drawable
 import android.text.TextUtils
 import androidx.activity.compose.ManagedActivityResultLauncher
@@ -40,6 +41,7 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.graphics.painter.Painter
 import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.TextLayoutResult
@@ -75,6 +77,7 @@
 import com.android.credentialmanager.model.get.RemoteEntryInfo
 import com.android.credentialmanager.userAndDisplayNameForPasskey
 import com.android.internal.logging.UiEventLogger.UiEventEnum
+import kotlin.math.max
 
 @Composable
 fun GetCredentialScreen(
@@ -110,16 +113,29 @@
                     ProviderActivityState.NOT_APPLICABLE -> {
                         if (getCredentialUiState.currentScreenState
                             == GetScreenState.PRIMARY_SELECTION) {
-                            PrimarySelectionCard(
-                                requestDisplayInfo = getCredentialUiState.requestDisplayInfo,
-                                providerDisplayInfo = getCredentialUiState.providerDisplayInfo,
-                                providerInfoList = getCredentialUiState.providerInfoList,
-                                activeEntry = getCredentialUiState.activeEntry,
-                                onEntrySelected = viewModel::getFlowOnEntrySelected,
-                                onConfirm = viewModel::getFlowOnConfirmEntrySelected,
-                                onMoreOptionSelected = viewModel::getFlowOnMoreOptionSelected,
-                                onLog = { viewModel.logUiEvent(it) },
-                            )
+                            if (selectorUiImprovementsEnabled()) {
+                                PrimarySelectionCardVImpl(
+                                    requestDisplayInfo = getCredentialUiState.requestDisplayInfo,
+                                    providerDisplayInfo = getCredentialUiState.providerDisplayInfo,
+                                    providerInfoList = getCredentialUiState.providerInfoList,
+                                    activeEntry = getCredentialUiState.activeEntry,
+                                    onEntrySelected = viewModel::getFlowOnEntrySelected,
+                                    onConfirm = viewModel::getFlowOnConfirmEntrySelected,
+                                    onMoreOptionSelected = viewModel::getFlowOnMoreOptionSelected,
+                                    onLog = { viewModel.logUiEvent(it) },
+                                )
+                            } else {
+                                PrimarySelectionCard(
+                                    requestDisplayInfo = getCredentialUiState.requestDisplayInfo,
+                                    providerDisplayInfo = getCredentialUiState.providerDisplayInfo,
+                                    providerInfoList = getCredentialUiState.providerInfoList,
+                                    activeEntry = getCredentialUiState.activeEntry,
+                                    onEntrySelected = viewModel::getFlowOnEntrySelected,
+                                    onConfirm = viewModel::getFlowOnConfirmEntrySelected,
+                                    onMoreOptionSelected = viewModel::getFlowOnMoreOptionSelected,
+                                    onLog = { viewModel.logUiEvent(it) },
+                                )
+                            }
                             viewModel.uiMetrics.log(GetCredentialEvent
                                     .CREDMAN_GET_CRED_SCREEN_PRIMARY_SELECTION)
                         } else {
@@ -174,7 +190,8 @@
     }
 }
 
-/** Draws the primary credential selection page. */
+/** Draws the primary credential selection page, used in Android U. */
+// TODO(b/327518384) - remove after flag selectorUiImprovementsEnabled is enabled.
 @Composable
 fun PrimarySelectionCard(
     requestDisplayInfo: RequestDisplayInfo,
@@ -358,6 +375,202 @@
     onLog(GetCredentialEvent.CREDMAN_GET_CRED_PRIMARY_SELECTION_CARD)
 }
 
+internal const val MAX_ENTRY_FOR_PRIMARY_PAGE = 4
+
+/** Draws the primary credential selection page, used starting from android V. */
+@Composable
+fun PrimarySelectionCardVImpl(
+    requestDisplayInfo: RequestDisplayInfo,
+    providerDisplayInfo: ProviderDisplayInfo,
+    providerInfoList: List<ProviderInfo>,
+    activeEntry: EntryInfo?,
+    onEntrySelected: (EntryInfo) -> Unit,
+    onConfirm: () -> Unit,
+    onMoreOptionSelected: () -> Unit,
+    onLog: @Composable (UiEventEnum) -> Unit,
+) {
+    val showMoreForTruncatedEntry = remember { mutableStateOf(false) }
+    val sortedUserNameToCredentialEntryList =
+        providerDisplayInfo.sortedUserNameToCredentialEntryList
+    val authenticationEntryList = providerDisplayInfo.authenticationEntryList
+    // Show at most 4 entries (credential type or locked type) in this primary page
+    val primaryPageCredentialEntryList =
+        sortedUserNameToCredentialEntryList.take(MAX_ENTRY_FOR_PRIMARY_PAGE)
+    val primaryPageLockedEntryList = authenticationEntryList.take(
+        max(0, MAX_ENTRY_FOR_PRIMARY_PAGE - primaryPageCredentialEntryList.size)
+    )
+    SheetContainerCard {
+        val preferTopBrandingContent = requestDisplayInfo.preferTopBrandingContent
+        val singleProviderId = findSingleProviderIdForPrimaryPage(
+                primaryPageCredentialEntryList,
+                primaryPageLockedEntryList
+        )
+        if (preferTopBrandingContent != null) {
+            item {
+                HeadlineProviderIconAndName(
+                    preferTopBrandingContent.icon,
+                    preferTopBrandingContent.displayName
+                )
+            }
+        } else {
+            // When only one provider's entries will be displayed on the primary page, display that
+            // provider's icon + name up top.
+            if (singleProviderId != null) {
+                // First should always work but just to be safe.
+                val providerInfo = providerInfoList.firstOrNull { it.id == singleProviderId }
+                if (providerInfo != null) {
+                    item {
+                        HeadlineProviderIconAndName(
+                            providerInfo.icon,
+                            providerInfo.displayName
+                        )
+                    }
+                }
+            }
+        }
+
+        val hasSingleEntry = primaryPageCredentialEntryList.size +
+                primaryPageLockedEntryList.size == 1
+        item {
+            if (requestDisplayInfo.preferIdentityDocUi) {
+                HeadlineText(
+                    text = stringResource(
+                        if (hasSingleEntry) {
+                            R.string.get_dialog_title_use_info_on
+                        } else {
+                            R.string.get_dialog_title_choose_option_for
+                        },
+                        requestDisplayInfo.appName
+                    ),
+                )
+            } else {
+                HeadlineText(
+                    text = stringResource(
+                        if (hasSingleEntry) {
+                            val singleEntryType = primaryPageCredentialEntryList.firstOrNull()
+                                ?.sortedCredentialEntryList?.firstOrNull()?.credentialType
+                            if (singleEntryType == CredentialType.PASSKEY)
+                                R.string.get_dialog_title_use_passkey_for
+                            else if (singleEntryType == CredentialType.PASSWORD)
+                                R.string.get_dialog_title_use_password_for
+                            else if (authenticationEntryList.isNotEmpty())
+                                R.string.get_dialog_title_unlock_options_for
+                            else R.string.get_dialog_title_use_sign_in_for
+                        } else {
+                            if (authenticationEntryList.isNotEmpty() ||
+                                sortedUserNameToCredentialEntryList.any { perNameEntryList ->
+                                    perNameEntryList.sortedCredentialEntryList.any { entry ->
+                                        entry.credentialType != CredentialType.PASSWORD &&
+                                            entry.credentialType != CredentialType.PASSKEY
+                                    }
+                                }
+                            ) // For an unknown / locked entry, it's not true that it is
+                            // already saved, strictly speaking. Hence use a different title
+                            // without the mention of "saved"
+                                R.string.get_dialog_title_choose_sign_in_for
+                            else
+                                R.string.get_dialog_title_choose_saved_sign_in_for
+                        },
+                        requestDisplayInfo.appName
+                    ),
+                )
+            }
+        }
+        item { Divider(thickness = 24.dp, color = Color.Transparent) }
+        item {
+            CredentialContainerCard {
+                Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
+                    primaryPageCredentialEntryList.forEach {
+                        val entry = it.sortedCredentialEntryList.first()
+                        CredentialEntryRow(
+                                credentialEntryInfo = entry,
+                                onEntrySelected = onEntrySelected,
+                                enforceOneLine = true,
+                                onTextLayout = {
+                                    showMoreForTruncatedEntry.value = it.hasVisualOverflow
+                                },
+                                hasSingleEntry = hasSingleEntry,
+                                shouldOverrideIcon = entry.isDefaultIconPreferredAsSingleProvider &&
+                                        (singleProviderId != null),
+                        )
+                    }
+                    primaryPageLockedEntryList.forEach {
+                        AuthenticationEntryRow(
+                                authenticationEntryInfo = it,
+                                onEntrySelected = onEntrySelected,
+                                enforceOneLine = true,
+                        )
+                    }
+                }
+            }
+        }
+        item { Divider(thickness = 24.dp, color = Color.Transparent) }
+        var totalEntriesCount = sortedUserNameToCredentialEntryList
+            .flatMap { it.sortedCredentialEntryList }.size + authenticationEntryList
+            .size + providerInfoList.flatMap { it.actionEntryList }.size
+        if (providerDisplayInfo.remoteEntry != null) totalEntriesCount += 1
+        // Row horizontalArrangement differs on only one actionButton(should place on most
+        // left)/only one confirmButton(should place on most right)/two buttons exist the same
+        // time(should be one on the left, one on the right)
+        item {
+            CtaButtonRow(
+                leftButton = if (totalEntriesCount > 1) {
+                    {
+                        ActionButton(
+                            stringResource(R.string.get_dialog_title_sign_in_options),
+                            onMoreOptionSelected
+                        )
+                    }
+                } else if (showMoreForTruncatedEntry.value) {
+                    {
+                        ActionButton(
+                            stringResource(R.string.button_label_view_more),
+                            onMoreOptionSelected
+                        )
+                    }
+                } else null,
+                rightButton = if (activeEntry != null) { // Only one sign-in options exist
+                    {
+                        ConfirmButton(
+                            stringResource(R.string.string_continue),
+                            onClick = onConfirm
+                        )
+                    }
+                } else null,
+            )
+        }
+    }
+    onLog(GetCredentialEvent.CREDMAN_GET_CRED_PRIMARY_SELECTION_CARD)
+}
+
+/**
+ * Attempt to find a single provider id, if it has supplied all the entries to be displayed on the
+ * front page; otherwise if multiple providers are found, return null.
+ */
+private fun findSingleProviderIdForPrimaryPage(
+    primaryPageCredentialEntryList: List<PerUserNameCredentialEntryList>,
+    primaryPageLockedEntryList: List<AuthenticationEntryInfo>
+): String? {
+    var providerId: String? = null
+    primaryPageCredentialEntryList.forEach {
+        val currProviderId = it.sortedCredentialEntryList.first().providerId
+        if (providerId == null) {
+            providerId = currProviderId
+        } else if (providerId != currProviderId) {
+            return null
+        }
+    }
+    primaryPageLockedEntryList.forEach {
+        val currProviderId = it.providerId
+        if (providerId == null) {
+            providerId = currProviderId
+        } else if (providerId != currProviderId) {
+            return null
+        }
+    }
+    return providerId
+}
+
 /** Draws the secondary credential selection page, where all sign-in options are listed. */
 @Composable
 fun AllSignInOptionCard(
@@ -540,29 +753,52 @@
     onEntrySelected: (EntryInfo) -> Unit,
     enforceOneLine: Boolean = false,
     onTextLayout: (TextLayoutResult) -> Unit = {},
+    // Make optional since the secondary page doesn't care about this value.
+    hasSingleEntry: Boolean? = null,
+    // For primary page only, if all display entries come from the same provider AND if that
+    // provider has opted in via isDefaultIconPreferredAsSingleProvider, then we override the
+    // display icon to the default icon for the given credential type.
+    shouldOverrideIcon: Boolean = false,
 ) {
     val (username, displayName) = if (credentialEntryInfo.credentialType == CredentialType.PASSKEY)
         userAndDisplayNameForPasskey(
             credentialEntryInfo.userName, credentialEntryInfo.displayName ?: "")
     else Pair(credentialEntryInfo.userName, credentialEntryInfo.displayName)
+
+    // For primary page, if
+    val overrideIcon: Painter? =
+        if (shouldOverrideIcon) {
+            when (credentialEntryInfo.credentialType) {
+                CredentialType.PASSKEY -> painterResource(R.drawable.ic_passkey_24)
+                CredentialType.PASSWORD -> painterResource(R.drawable.ic_password_24)
+                else -> painterResource(R.drawable.ic_other_sign_in_24)
+            }
+        } else null
+
     Entry(
         onClick = { onEntrySelected(credentialEntryInfo) },
-        iconImageBitmap = credentialEntryInfo.icon?.toBitmap()?.asImageBitmap(),
+        iconImageBitmap =
+        if (overrideIcon == null) credentialEntryInfo.icon?.toBitmap()?.asImageBitmap() else null,
         shouldApplyIconImageBitmapTint = credentialEntryInfo.shouldTintIcon,
         // Fall back to iconPainter if iconImageBitmap isn't available
         iconPainter =
-        if (credentialEntryInfo.icon == null) painterResource(R.drawable.ic_other_sign_in_24)
+        if (overrideIcon != null) overrideIcon
+        else if (credentialEntryInfo.icon == null) painterResource(R.drawable.ic_other_sign_in_24)
         else null,
         entryHeadlineText = username,
-        entrySecondLineText = if (
-            credentialEntryInfo.credentialType == CredentialType.PASSWORD) {
-            "••••••••••••"
-        } else {
-            val itemsToDisplay = listOf(
+        entrySecondLineText =
+        (if (hasSingleEntry != null && hasSingleEntry)
+            if (credentialEntryInfo.credentialType == CredentialType.PASSKEY ||
+                    credentialEntryInfo.credentialType == CredentialType.PASSWORD)
+                listOf(displayName)
+            // Still show the type display name for all non-password/passkey types since it won't be
+            // mentioned in the bottom sheet heading.
+            else listOf(displayName, credentialEntryInfo.credentialTypeDisplayName)
+        else listOf(
                 displayName,
                 credentialEntryInfo.credentialTypeDisplayName,
                 credentialEntryInfo.providerDisplayName
-            ).filterNot(TextUtils::isEmpty)
+        )).filterNot(TextUtils::isEmpty).let { itemsToDisplay ->
             if (itemsToDisplay.isEmpty()) null
             else itemsToDisplay.joinToString(
                 separator = stringResource(R.string.get_dialog_sign_in_type_username_separator)
@@ -570,6 +806,7 @@
         },
         enforceOneLine = enforceOneLine,
         onTextLayout = onTextLayout,
+        affiliatedDomainText = credentialEntryInfo.affiliatedDomain,
     )
 }
 
@@ -653,4 +890,4 @@
         contentText = stringResource(R.string.no_sign_in_info_in, lastLocked.providerDisplayName),
     )
     onLog(GetCredentialEvent.CREDMAN_GET_CRED_SCREEN_EMPTY_AUTH_SNACKBAR_SCREEN)
-}
\ No newline at end of file
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
index 458a99a..ef40188 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
@@ -16,10 +16,11 @@
 
 package com.android.credentialmanager.getflow
 
+import android.credentials.flags.Flags.selectorUiImprovementsEnabled
 import android.graphics.drawable.Drawable
+import androidx.credentials.PriorityHints
 import com.android.credentialmanager.model.get.ProviderInfo
 import com.android.credentialmanager.model.EntryInfo
-import com.android.credentialmanager.model.CredentialType
 import com.android.credentialmanager.model.get.AuthenticationEntryInfo
 import com.android.credentialmanager.model.get.CredentialEntryInfo
 import com.android.credentialmanager.model.get.RemoteEntryInfo
@@ -29,7 +30,8 @@
     val isRequestForAllOptions: Boolean,
     val providerInfoList: List<ProviderInfo>,
     val requestDisplayInfo: RequestDisplayInfo,
-    val providerDisplayInfo: ProviderDisplayInfo = toProviderDisplayInfo(providerInfoList),
+    val providerDisplayInfo: ProviderDisplayInfo =
+            toProviderDisplayInfo(providerInfoList, requestDisplayInfo.typePriorityMap),
     val currentScreenState: GetScreenState = toGetScreenState(
             providerDisplayInfo, isRequestForAllOptions),
     val activeEntry: EntryInfo? = toActiveEntry(providerDisplayInfo),
@@ -78,6 +80,8 @@
     val preferIdentityDocUi: Boolean,
     // A top level branding icon + display name preferred by the app.
     val preferTopBrandingContent: TopBrandingContent?,
+    // Map of credential type -> priority.
+    val typePriorityMap: Map<String, Int>,
 )
 
 data class TopBrandingContent(
@@ -118,7 +122,8 @@
  * @hide
  */
 fun toProviderDisplayInfo(
-    providerInfoList: List<ProviderInfo>
+    providerInfoList: List<ProviderInfo>,
+    typePriorityMap: Map<String, Int>,
 ): ProviderDisplayInfo {
     val userNameToCredentialEntryMap = mutableMapOf<String, MutableList<CredentialEntryInfo>>()
     val authenticationEntryList = mutableListOf<AuthenticationEntryInfo>()
@@ -133,7 +138,7 @@
 
         providerInfo.credentialEntryList.forEach {
             userNameToCredentialEntryMap.compute(
-                it.userName
+                if (selectorUiImprovementsEnabled()) it.entryGroupId else it.userName
             ) { _, v ->
                 if (v == null) {
                     mutableListOf(it)
@@ -146,7 +151,7 @@
     }
 
     // Compose sortedUserNameToCredentialEntryList
-    val comparator = CredentialEntryInfoComparatorByTypeThenTimestamp()
+    val comparator = CredentialEntryInfoComparatorByTypeThenTimestamp(typePriorityMap)
     // Sort per username
     userNameToCredentialEntryMap.values.forEach {
         it.sortWith(comparator)
@@ -202,13 +207,21 @@
     else GetScreenState.PRIMARY_SELECTION
 }
 
-internal class CredentialEntryInfoComparatorByTypeThenTimestamp : Comparator<CredentialEntryInfo> {
+internal class CredentialEntryInfoComparatorByTypeThenTimestamp(
+        val typePriorityMap: Map<String, Int>,
+) : Comparator<CredentialEntryInfo> {
     override fun compare(p0: CredentialEntryInfo, p1: CredentialEntryInfo): Int {
         // First prefer passkey type for its security benefits
-        if (p0.credentialType != p1.credentialType) {
-            if (CredentialType.PASSKEY == p0.credentialType) {
+        if (p0.rawCredentialType != p1.rawCredentialType) {
+            val p0Priority = typePriorityMap.getOrDefault(
+                    p0.rawCredentialType, PriorityHints.PRIORITY_DEFAULT
+            )
+            val p1Priority = typePriorityMap.getOrDefault(
+                    p1.rawCredentialType, PriorityHints.PRIORITY_DEFAULT
+            )
+            if (p0Priority < p1Priority) {
                 return -1
-            } else if (CredentialType.PASSKEY == p1.credentialType) {
+            } else if (p1Priority < p0Priority) {
                 return 1
             }
         }
diff --git a/packages/CredentialManager/tests/robotests/Android.bp b/packages/CredentialManager/tests/robotests/Android.bp
index baebfeb..75a0dcc 100644
--- a/packages/CredentialManager/tests/robotests/Android.bp
+++ b/packages/CredentialManager/tests/robotests/Android.bp
@@ -37,7 +37,7 @@
         ":CredentialManagerScreenshotTestFiles",
     ],
 
-    // Do not add any libraries here, instead add them to the ScreenshotTestStub
+    // Do not add any libraries here, instead add them to the ScreenshotTestRobo
     static_libs: [
         "androidx.compose.runtime_runtime",
         "androidx.test.uiautomator_uiautomator",
@@ -45,6 +45,7 @@
         "inline-mockito-robolectric-prebuilt",
         "platform-parametric-runner-lib",
         "uiautomator-helpers",
+        "flag-junit-base",
     ],
     libs: [
         "android.test.runner",
diff --git a/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_landscape_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_landscape_singleCredentialScreen_newM3BottomSheet.png
new file mode 100644
index 0000000..81860e5
--- /dev/null
+++ b/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_landscape_singleCredentialScreen_newM3BottomSheet.png
Binary files differ
diff --git a/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_portrait_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_portrait_singleCredentialScreen_newM3BottomSheet.png
new file mode 100644
index 0000000..8c1fff7
--- /dev/null
+++ b/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_portrait_singleCredentialScreen_newM3BottomSheet.png
Binary files differ
diff --git a/packages/CredentialManager/tests/robotests/customization/assets/phone/light_landscape_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/phone/light_landscape_singleCredentialScreen_newM3BottomSheet.png
new file mode 100644
index 0000000..4eb025f
--- /dev/null
+++ b/packages/CredentialManager/tests/robotests/customization/assets/phone/light_landscape_singleCredentialScreen_newM3BottomSheet.png
Binary files differ
diff --git a/packages/CredentialManager/tests/robotests/customization/assets/phone/light_portrait_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/phone/light_portrait_singleCredentialScreen_newM3BottomSheet.png
new file mode 100644
index 0000000..c709f93
--- /dev/null
+++ b/packages/CredentialManager/tests/robotests/customization/assets/phone/light_portrait_singleCredentialScreen_newM3BottomSheet.png
Binary files differ
diff --git a/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_landscape_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_landscape_singleCredentialScreen_newM3BottomSheet.png
new file mode 100644
index 0000000..278c13f
--- /dev/null
+++ b/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_landscape_singleCredentialScreen_newM3BottomSheet.png
Binary files differ
diff --git a/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_portrait_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_portrait_singleCredentialScreen_newM3BottomSheet.png
new file mode 100644
index 0000000..cb85df3
--- /dev/null
+++ b/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_portrait_singleCredentialScreen_newM3BottomSheet.png
Binary files differ
diff --git a/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_landscape_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_landscape_singleCredentialScreen_newM3BottomSheet.png
new file mode 100644
index 0000000..2eca707
--- /dev/null
+++ b/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_landscape_singleCredentialScreen_newM3BottomSheet.png
Binary files differ
diff --git a/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_portrait_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_portrait_singleCredentialScreen_newM3BottomSheet.png
new file mode 100644
index 0000000..7ee91b3
--- /dev/null
+++ b/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_portrait_singleCredentialScreen_newM3BottomSheet.png
Binary files differ
diff --git a/packages/CredentialManager/tests/robotests/screenshot/src/com/android/credentialmanager/GetCredScreenshotTest.kt b/packages/CredentialManager/tests/robotests/screenshot/src/com/android/credentialmanager/GetCredScreenshotTest.kt
index a0e1fed..28d83ee 100644
--- a/packages/CredentialManager/tests/robotests/screenshot/src/com/android/credentialmanager/GetCredScreenshotTest.kt
+++ b/packages/CredentialManager/tests/robotests/screenshot/src/com/android/credentialmanager/GetCredScreenshotTest.kt
@@ -16,7 +16,10 @@
 
 package com.android.credentialmanager
 
+import android.credentials.flags.Flags
 import android.content.Context
+import android.platform.test.flag.junit.SetFlagsRule
+import androidx.compose.ui.test.isPopup
 import com.android.credentialmanager.getflow.RequestDisplayInfo
 import com.android.credentialmanager.model.CredentialType
 import com.android.credentialmanager.model.get.ProviderInfo
@@ -50,6 +53,7 @@
                 preferImmediatelyAvailableCredentials = false,
                 preferIdentityDocUi = false,
                 preferTopBrandingContent = null,
+                typePriorityMap = emptyMap(),
         )
     }
 
@@ -59,10 +63,13 @@
             CredentialManagerGoldenImagePathManager(getEmulatedDevicePathConfig(emulationSpec))
     )
 
+    @get:Rule val setFlagsRule: SetFlagsRule = SetFlagsRule()
+
     @Test
-    fun singleCredentialScreen() {
+    fun singleCredentialScreen_M3BottomSheetDisabled() {
+        setFlagsRule.disableFlags(Flags.FLAG_SELECTOR_UI_IMPROVEMENTS_ENABLED)
         val providerInfoList = buildProviderInfoList()
-        val providerDisplayInfo = toProviderDisplayInfo(providerInfoList)
+        val providerDisplayInfo = toProviderDisplayInfo(providerInfoList, emptyMap())
         val activeEntry = toActiveEntry(providerDisplayInfo)
         screenshotRule.screenshotTest("singleCredentialScreen") {
             ModalBottomSheet(
@@ -86,6 +93,39 @@
         }
     }
 
+    @Test
+    fun singleCredentialScreen_M3BottomSheetEnabled() {
+        setFlagsRule.enableFlags(Flags.FLAG_SELECTOR_UI_IMPROVEMENTS_ENABLED)
+        val providerInfoList = buildProviderInfoList()
+        val providerDisplayInfo = toProviderDisplayInfo(providerInfoList, emptyMap())
+        val activeEntry = toActiveEntry(providerDisplayInfo)
+        screenshotRule.screenshotTest(
+                "singleCredentialScreen_newM3BottomSheet",
+                // M3's ModalBottomSheet lives in a new window, meaning we have two windows with
+                // a root. Hence use a different matcher `isPopup`.
+                viewFinder = { screenshotRule.composeRule.onNode(isPopup()) },
+        ) {
+            ModalBottomSheet(
+                    sheetContent = {
+                        PrimarySelectionCard(
+                                requestDisplayInfo = REQUEST_DISPLAY_INFO,
+                                providerDisplayInfo = providerDisplayInfo,
+                                providerInfoList = providerInfoList,
+                                activeEntry = activeEntry,
+                                onEntrySelected = {},
+                                onConfirm = {},
+                                onMoreOptionSelected = {},
+                                onLog = {},
+                        )
+                    },
+                    isInitialRender = true,
+                    onDismiss = {},
+                    onInitialRenderComplete = {},
+                    isAutoSelectFlow = false,
+            )
+        }
+    }
+
     private fun buildProviderInfoList(): List<ProviderInfo> {
         val context = ApplicationProvider.getApplicationContext<Context>()
         val provider1 = ProviderInfo(
@@ -107,7 +147,11 @@
                                 icon = null,
                                 shouldTintIcon = true,
                                 lastUsedTimeMillis = null,
-                                isAutoSelectable = false
+                                isAutoSelectable = false,
+                                entryGroupId = "username",
+                                isDefaultIconPreferredAsSingleProvider = false,
+                                rawCredentialType = "unknown-type",
+                                affiliatedDomain = null,
                         )
                 ),
                 authenticationEntryList = emptyList(),
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
index 463c4d1..66be7ba 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
@@ -29,10 +29,14 @@
 import com.android.credentialmanager.model.get.CredentialEntryInfo
 import com.android.credentialmanager.ui.mappers.toGet
 import android.util.Log
+import androidx.activity.compose.rememberLauncherForActivityResult
+import androidx.compose.runtime.Composable
 import com.android.credentialmanager.CredentialSelectorUiState.Cancel
 import com.android.credentialmanager.CredentialSelectorUiState.Close
 import com.android.credentialmanager.CredentialSelectorUiState.Create
 import com.android.credentialmanager.CredentialSelectorUiState.Idle
+import com.android.credentialmanager.activity.StartBalIntentSenderForResultContract
+import com.android.credentialmanager.ktx.getIntentSenderRequest
 import dagger.hilt.android.lifecycle.HiltViewModel
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
@@ -47,6 +51,8 @@
 ) : FlowEngine, ViewModel() {
     private val isPrimaryScreen = MutableStateFlow(true)
     private val shouldClose = MutableStateFlow(false)
+    private lateinit var selectedEntry: EntryInfo
+    private var isAutoSelected: Boolean = false
     val uiState: StateFlow<CredentialSelectorUiState> =
         combine(
             credentialManagerClient.requests,
@@ -108,6 +114,25 @@
         )
         shouldClose.value = result
     }
+
+    @Composable
+    override fun getEntrySelector(): (entry: EntryInfo, isAutoSelected: Boolean) -> Unit {
+        val launcher = rememberLauncherForActivityResult(
+            StartBalIntentSenderForResultContract()
+        ) {
+            sendSelectionResult(entryInfo = selectedEntry,
+                resultCode = it.resultCode,
+                resultData = it.data,
+                isAutoSelected = isAutoSelected)
+        }
+        return { selected, autoSelect ->
+            selectedEntry = selected
+            isAutoSelected = autoSelect
+            selected.getIntentSenderRequest()?.let {
+                launcher.launch(it)
+            } ?: Log.w(TAG, "Cannot parse IntentSenderRequest")
+        }
+    }
 }
 
 sealed class CredentialSelectorUiState {
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/FlowEngine.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/FlowEngine.kt
index e421644..2e80a7c 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/FlowEngine.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/FlowEngine.kt
@@ -17,6 +17,8 @@
 package com.android.credentialmanager
 
 import android.content.Intent
+import androidx.activity.result.IntentSenderRequest
+import androidx.compose.runtime.Composable
 import com.android.credentialmanager.model.EntryInfo
 
 /** Engine of the credential selecting flow. */
@@ -42,4 +44,14 @@
         resultData: Intent? = null,
         isAutoSelected: Boolean = false,
     )
+
+    /**
+     * Helper function to get an entry selector.
+     *
+     * @return selector fun consumes selected [EntryInfo]. Once invoked, [IntentSenderRequest] would
+     * be launched and invocation of [sendSelectionResult] would happen right after launching result
+     * coming back.
+     */
+    @Composable
+    fun getEntrySelector(): (entry: EntryInfo, isAutoSelected: Boolean) -> Unit
 }
\ No newline at end of file
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt
index f9a58871..405de1d3 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt
@@ -43,6 +43,7 @@
 import com.google.android.horologist.compose.navscaffold.composable
 import com.google.android.horologist.compose.navscaffold.scrollable
 import com.android.credentialmanager.model.CredentialType
+import com.android.credentialmanager.model.EntryInfo
 import com.android.credentialmanager.ui.screens.multiple.MultiCredentialsFoldScreen
 
 @OptIn(ExperimentalHorologistApi::class)
@@ -56,6 +57,7 @@
     val swipeToDismissBoxState = rememberSwipeToDismissBoxState()
     val navHostState =
         rememberSwipeDismissableNavHostState(swipeToDismissBoxState = swipeToDismissBoxState)
+    val selectEntry = flowEngine.getEntrySelector()
 
     val uiState by viewModel.uiState.collectAsStateWithLifecycle()
     WearNavScaffold(
@@ -111,6 +113,7 @@
                 navController = navController,
                 state = state,
                 onCloseApp = onCloseApp,
+                selectEntry = selectEntry
             )
         }
 
@@ -133,9 +136,14 @@
     navController: NavController,
     state: CredentialSelectorUiState.Get,
     onCloseApp: () -> Unit,
+    selectEntry: (entry: EntryInfo, isAutoSelected: Boolean) -> Unit,
 ) {
     when (state) {
         is SingleEntry -> {
+            if (state.entry.isAutoSelectable) {
+                selectEntry(state.entry, true)
+                return
+            }
             when (state.entry.credentialType) {
                 CredentialType.UNKNOWN -> {
                     navController.navigateToSignInWithProviderScreen()
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt
index 1f1a296..2ca8ef1 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt
@@ -18,8 +18,6 @@
 
 package com.android.credentialmanager.ui.screens.single.password
 
-import android.util.Log
-import androidx.activity.compose.rememberLauncherForActivityResult
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
@@ -28,9 +26,6 @@
 import androidx.compose.ui.unit.dp
 import com.android.credentialmanager.FlowEngine
 import com.android.credentialmanager.R
-import com.android.credentialmanager.TAG
-import com.android.credentialmanager.activity.StartBalIntentSenderForResultContract
-import com.android.credentialmanager.ktx.getIntentSenderRequest
 import com.android.credentialmanager.ui.components.PasswordRow
 import com.android.credentialmanager.ui.components.ContinueChip
 import com.android.credentialmanager.ui.components.DismissChip
@@ -57,11 +52,7 @@
     modifier: Modifier = Modifier,
     flowEngine: FlowEngine,
 ) {
-    val launcher = rememberLauncherForActivityResult(
-        StartBalIntentSenderForResultContract()
-    ) {
-        flowEngine.sendSelectionResult(entry, it.resultCode, it.data)
-    }
+    val selectEntry = flowEngine.getEntrySelector()
     SingleAccountScreen(
         headerContent = {
             SignInHeader(
@@ -80,11 +71,7 @@
     ) {
         item {
             Column {
-                ContinueChip {
-                    entry.getIntentSenderRequest()?.let {
-                        launcher.launch(it)
-                    } ?: Log.w(TAG, "Cannot parse IntentSenderRequest")
-                }
+                ContinueChip { selectEntry(entry, false) }
                 SignInOptionsChip{ flowEngine.openSecondaryScreen() }
                 DismissChip { flowEngine.cancel() }
             }
diff --git a/packages/EasterEgg/Android.bp b/packages/EasterEgg/Android.bp
index 0caf505..6f4f9ca 100644
--- a/packages/EasterEgg/Android.bp
+++ b/packages/EasterEgg/Android.bp
@@ -48,6 +48,8 @@
     },
 
     static_libs: [
+        "easter_egg_flags_lib",
+
         "androidx.core_core",
         "androidx.annotation_annotation",
         "androidx.recyclerview_recyclerview",
@@ -72,3 +74,16 @@
 
     kotlincflags: ["-Xjvm-default=all"],
 }
+
+java_aconfig_library {
+    name: "easter_egg_flags_lib",
+    aconfig_declarations: "easter_egg_flags",
+}
+
+aconfig_declarations {
+    name: "easter_egg_flags",
+    package: "com.android.egg.flags",
+    srcs: [
+        "easter_egg_flags.aconfig",
+    ],
+}
diff --git a/packages/EasterEgg/easter_egg_flags.aconfig b/packages/EasterEgg/easter_egg_flags.aconfig
new file mode 100644
index 0000000..3268a4f
--- /dev/null
+++ b/packages/EasterEgg/easter_egg_flags.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.egg.flags"
+
+flag {
+    name: "flag_flag"
+    namespace: "systemui"
+    description: "Flags are planted on planets when you land. Yes, it's a flag for flags."
+    bug: "320150798"
+}
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Universe.kt b/packages/EasterEgg/src/com/android/egg/landroid/Universe.kt
index fec3ab3..11dce61 100644
--- a/packages/EasterEgg/src/com/android/egg/landroid/Universe.kt
+++ b/packages/EasterEgg/src/com/android/egg/landroid/Universe.kt
@@ -174,7 +174,9 @@
 
         ship = Spacecraft()
 
-        ship.pos = star.pos + Vec2.makeWithAngleMag(PIf / 4, PLANET_ORBIT_RANGE.start)
+        // in the test universe, start the ship near the outermost planet
+        ship.pos = planets.last().pos + Vec2(planets.first().radius * 1.5f, 0f)
+
         ship.angle = 0f
         add(ship)
 
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt b/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt
index 24b9c6a..6baf36e 100644
--- a/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt
+++ b/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt
@@ -31,6 +31,8 @@
 import java.lang.Float.max
 import kotlin.math.sqrt
 
+import com.android.egg.flags.Flags.flagFlag
+
 const val DRAW_ORBITS = true
 const val DRAW_GRAVITATIONAL_FIELDS = true
 const val DRAW_STAR_GRAVITATIONAL_FIELDS = true
@@ -279,8 +281,23 @@
 
 fun ZoomedDrawScope.drawLanding(landing: Landing) {
     val v = landing.planet.pos + Vec2.makeWithAngleMag(landing.angle, landing.planet.radius)
-    drawLine(Color.Red, v + Vec2(-5f, -5f), v + Vec2(5f, 5f), strokeWidth = 1f / zoom)
-    drawLine(Color.Red, v + Vec2(5f, -5f), v + Vec2(-5f, 5f), strokeWidth = 1f / zoom)
+
+    if (flagFlag()) {
+        val strokeWidth = 2f / zoom
+        val height = 80f
+        rotateRad(landing.angle, pivot = v) {
+            translate(v.x, v.y) {
+                drawPath(
+                    Path().apply {
+                        moveTo(0f, 0f)
+                        lineTo(height, 0f)
+                        lineTo(height * 0.875f, height * 0.25f)
+                        lineTo(height * 0.75f, 0f)
+                        close()
+                    }, Color.Yellow, style = Stroke(width = strokeWidth))
+            }
+        }
+    }
 }
 
 fun ZoomedDrawScope.drawSpark(spark: Spark) {
diff --git a/packages/PackageInstaller/res/layout/install_content_view.xml b/packages/PackageInstaller/res/layout/install_content_view.xml
index 2ecd2d5..524a88a 100644
--- a/packages/PackageInstaller/res/layout/install_content_view.xml
+++ b/packages/PackageInstaller/res/layout/install_content_view.xml
@@ -24,114 +24,116 @@
     android:paddingLeft="?android:attr/dialogPreferredPadding"
     android:paddingRight="?android:attr/dialogPreferredPadding">
 
-    <LinearLayout
-        android:id="@+id/staging"
+  <LinearLayout
+      android:id="@+id/staging"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:orientation="vertical"
+      android:visibility="invisible">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        style="@android:style/TextAppearance.Material.Subhead"
+        android:text="@string/message_staging" />
+
+    <ProgressBar
+        android:id="@+id/progress_indeterminate"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:visibility="invisible">
+        android:paddingTop="8dp"
+        style="?android:attr/progressBarStyleHorizontal"
+        android:indeterminate="true" />
 
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            style="@android:style/TextAppearance.Material.Subhead"
-            android:text="@string/message_staging" />
+  </LinearLayout>
 
-        <ProgressBar
-            android:id="@+id/progress_indeterminate"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingTop="8dp"
-            style="?android:attr/progressBarStyleHorizontal"
-            android:indeterminate="true" />
+  <LinearLayout
+      android:id="@+id/installing"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:orientation="vertical"
+      android:visibility="invisible">
 
-    </LinearLayout>
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        style="@android:style/TextAppearance.Material.Subhead"
+        android:text="@string/installing" />
 
-    <LinearLayout
-        android:id="@+id/installing"
+    <ProgressBar
+        android:id="@+id/progress"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:visibility="invisible">
+        android:paddingTop="8dp"
+        style="?android:attr/progressBarStyleHorizontal"
+        android:indeterminate="true" />
 
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            style="@android:style/TextAppearance.Material.Subhead"
-            android:text="@string/installing" />
+  </LinearLayout>
 
-        <ProgressBar
-            android:id="@+id/progress"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingTop="8dp"
-            style="?android:attr/progressBarStyleHorizontal"
-            android:indeterminate="true" />
+  <TextView
+      android:id="@+id/install_confirm_question"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      style="@android:style/TextAppearance.Material.Subhead"
+      android:text="@string/install_confirm_question"
+      android:visibility="invisible"
+      android:scrollbars="vertical" />
 
-    </LinearLayout>
+  <TextView
+      android:id="@+id/install_confirm_question_update"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      style="@android:style/TextAppearance.Material.Subhead"
+      android:text="@string/install_confirm_question_update"
+      android:visibility="invisible"
+      android:scrollbars="vertical" />
 
-    <TextView
-        android:id="@+id/install_confirm_question"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        style="@android:style/TextAppearance.Material.Subhead"
-        android:text="@string/install_confirm_question"
-        android:visibility="invisible" />
+  <TextView
+      android:id="@+id/install_success"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      style="@android:style/TextAppearance.Material.Subhead"
+      android:text="@string/install_done"
+      android:visibility="invisible" />
 
-    <TextView
-        android:id="@+id/install_confirm_question_update"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        style="@android:style/TextAppearance.Material.Subhead"
-        android:text="@string/install_confirm_question_update"
-        android:visibility="invisible" />
+  <TextView
+      android:id="@+id/install_failed"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      style="@android:style/TextAppearance.Material.Subhead"
+      android:text="@string/install_failed"
+      android:visibility="invisible" />
 
-    <TextView
-        android:id="@+id/install_success"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        style="@android:style/TextAppearance.Material.Subhead"
-        android:text="@string/install_done"
-        android:visibility="invisible" />
+  <TextView
+      android:id="@+id/install_failed_blocked"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      style="@android:style/TextAppearance.Material.Subhead"
+      android:text="@string/install_failed_blocked"
+      android:visibility="invisible" />
 
-    <TextView
-        android:id="@+id/install_failed"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        style="@android:style/TextAppearance.Material.Subhead"
-        android:text="@string/install_failed"
-        android:visibility="invisible" />
+  <TextView
+      android:id="@+id/install_failed_conflict"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      style="@android:style/TextAppearance.Material.Subhead"
+      android:text="@string/install_failed_conflict"
+      android:visibility="invisible" />
 
-    <TextView
-        android:id="@+id/install_failed_blocked"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        style="@android:style/TextAppearance.Material.Subhead"
-        android:text="@string/install_failed_blocked"
-        android:visibility="invisible" />
+  <TextView
+      android:id="@+id/install_failed_incompatible"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      style="@android:style/TextAppearance.Material.Subhead"
+      android:text="@string/install_failed_incompatible"
+      android:visibility="invisible" />
 
-    <TextView
-        android:id="@+id/install_failed_conflict"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        style="@android:style/TextAppearance.Material.Subhead"
-        android:text="@string/install_failed_conflict"
-        android:visibility="invisible" />
+  <TextView
+      android:id="@+id/install_failed_invalid_apk"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      style="@android:style/TextAppearance.Material.Subhead"
+      android:text="@string/install_failed_invalid_apk"
+      android:visibility="invisible" />
 
-    <TextView
-        android:id="@+id/install_failed_incompatible"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        style="@android:style/TextAppearance.Material.Subhead"
-        android:text="@string/install_failed_incompatible"
-        android:visibility="invisible" />
-
-    <TextView
-        android:id="@+id/install_failed_invalid_apk"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        style="@android:style/TextAppearance.Material.Subhead"
-        android:text="@string/install_failed_invalid_apk"
-        android:visibility="invisible" />
-
-</FrameLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/PackageInstaller/res/layout/uninstall_content_view.xml b/packages/PackageInstaller/res/layout/uninstall_content_view.xml
index 5666c0e..434e333 100644
--- a/packages/PackageInstaller/res/layout/uninstall_content_view.xml
+++ b/packages/PackageInstaller/res/layout/uninstall_content_view.xml
@@ -18,31 +18,36 @@
 <!-- Check box that is displayed in the activity resolver UI for the user
      to make their selection the preferred activity. -->
 
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:theme="?android:attr/alertDialogTheme"
-    android:orientation="vertical"
-    android:paddingTop="8dp"
-    android:paddingStart="?android:attr/dialogPreferredPadding"
-    android:paddingEnd="?android:attr/dialogPreferredPadding"
-    android:clipToPadding="false">
+    android:layout_height="wrap_content">
 
-    <TextView
-        android:id="@+id/message"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        style="@android:style/TextAppearance.Material.Subhead" />
+  <LinearLayout
+      xmlns:android="http://schemas.android.com/apk/res/android"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:theme="?android:attr/alertDialogTheme"
+      android:orientation="vertical"
+      android:paddingTop="8dp"
+      android:paddingStart="?android:attr/dialogPreferredPadding"
+      android:paddingEnd="?android:attr/dialogPreferredPadding"
+      android:clipToPadding="false">
 
-    <CheckBox
-        android:id="@+id/keepData"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="8dp"
-        android:layout_marginStart="-8dp"
-        android:paddingLeft="8sp"
-        android:visibility="gone"
-        style="@android:style/TextAppearance.Material.Subhead" />
+      <TextView
+          android:id="@+id/message"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+          style="@android:style/TextAppearance.Material.Subhead" />
 
-</LinearLayout>
\ No newline at end of file
+      <CheckBox
+          android:id="@+id/keepData"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:layout_marginTop="8dp"
+          android:layout_marginStart="-8dp"
+          android:paddingLeft="8sp"
+          android:visibility="gone"
+          style="@android:style/TextAppearance.Material.Subhead" />
+
+  </LinearLayout>
+</ScrollView>
diff --git a/packages/PackageInstaller/res/values-el/strings.xml b/packages/PackageInstaller/res/values-el/strings.xml
index 61aa4e6..3c37df6 100644
--- a/packages/PackageInstaller/res/values-el/strings.xml
+++ b/packages/PackageInstaller/res/values-el/strings.xml
@@ -117,7 +117,7 @@
     <string name="unarchive_error_generic_title" msgid="7123457671482449992">"Κάτι πήγε στραβά"</string>
     <string name="unarchive_error_generic_body" msgid="4486803312463813079">"Παρουσιάστηκε κάποιο πρόβλημα κατά την επαναφορά αυτής της εφαρμογής"</string>
     <string name="unarchive_error_storage_title" msgid="5080723357273852630">"Δεν επαρκεί ο αποθηκευτικός χώρος"</string>
-    <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Για να επαναφέρετε αυτή την εφαρμογή, μπορείτε να ελευθερώσετε χώρο στη συσκευή. Απαιτούμενος αποθηκευτικός χώρος: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
+    <string name="unarchive_error_storage_body" msgid="6879544407568780524">"Για να επαναφέρετε αυτή την εφαρμογή, μπορείτε να αποδεσμεύσετε χώρο στη συσκευή. Απαιτούμενος αποθηκευτικός χώρος: <xliff:g id="BYTES">%1$s</xliff:g>"</string>
     <string name="unarchive_action_required_title" msgid="4971245740162604619">"Απαιτούμενη ενέργεια"</string>
     <string name="unarchive_action_required_body" msgid="1679431572983989231">"Ακολουθήστε τα επόμενα βήματα για να επαναφέρετε αυτή την εφαρμογή"</string>
     <string name="unarchive_error_installer_disabled_title" msgid="4815715617014985605">"Το <xliff:g id="INSTALLERNAME">%1$s</xliff:g> είναι απενεργοποιημένο"</string>
diff --git a/packages/PackageInstaller/res/values-fr/strings.xml b/packages/PackageInstaller/res/values-fr/strings.xml
index 5311903..ee0c752 100644
--- a/packages/PackageInstaller/res/values-fr/strings.xml
+++ b/packages/PackageInstaller/res/values-fr/strings.xml
@@ -98,9 +98,9 @@
     <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Pour votre sécurité, l\'installation d\'applis inconnues provenant de cette source n\'est pas autorisée sur ce téléviseur actuellement. Vous pouvez modifier cette option dans les paramètres."</string>
     <string name="untrusted_external_source_warning" product="watch" msgid="7195163388090818636">"Pour votre sécurité, l\'installation d\'applis inconnues provenant de cette source n\'est pas autorisée sur cette montre actuellement. Vous pouvez modifier cette option dans les paramètres."</string>
     <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Pour votre sécurité, l\'installation d\'applis inconnues provenant de cette source n\'est pas autorisée sur ce téléphone actuellement. Vous pouvez modifier cette option dans les paramètres."</string>
-    <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Votre téléphone et vos données à caractère personnel sont plus vulnérables aux attaques d\'applications inconnues. En installant cette application, vous acceptez d\'être le seul responsable de tout dommage causé à votre téléphone ou de toute perte de données pouvant découler de son utilisation."</string>
-    <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Votre tablette et vos données à caractère personnel sont plus vulnérables aux attaques d\'applications inconnues. En installant cette application, vous acceptez d\'être le seul responsable de tout dommage causé à votre tablette ou de toute perte de données pouvant découler de son utilisation."</string>
-    <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Votre téléviseur et vos données à caractère personnel sont plus vulnérables aux attaques d\'applications inconnues. En installant cette application, vous acceptez d\'être le seul responsable de tout dommage causé à votre téléviseur ou de toute perte de données pouvant découler de son utilisation."</string>
+    <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Votre téléphone et vos données à caractère personnel sont plus vulnérables aux attaques d\'applications inconnues. En installant cette application, vous acceptez d\'être l\'unique responsable de tout dommage causé à votre téléphone ou de toute perte de données pouvant découler de son utilisation."</string>
+    <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Votre tablette et vos données à caractère personnel sont plus vulnérables aux attaques d\'applications inconnues. En installant cette application, vous acceptez d\'être l\'unique responsable de tout dommage causé à votre tablette ou de toute perte de données pouvant découler de son utilisation."</string>
+    <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Votre téléviseur et vos données à caractère personnel sont plus vulnérables aux attaques d\'applications inconnues. En installant cette application, vous acceptez d\'être l\'unique responsable de tout dommage causé à votre téléviseur ou de toute perte de données pouvant découler de son utilisation."</string>
     <string name="cloned_app_label" msgid="7503612829833756160">"Clone de <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string>
     <string name="archiving_app_label" msgid="1127085259724124725">"Archiver <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ?"</string>
     <string name="anonymous_source_continue" msgid="4375745439457209366">"Continuer"</string>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index cf6aab6..e95a8e6 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -51,6 +51,7 @@
 import android.text.Html;
 import android.text.Spanned;
 import android.text.TextUtils;
+import android.text.method.ScrollingMovementMethod;
 import android.util.Log;
 import android.view.View;
 import android.widget.Button;
@@ -174,6 +175,7 @@
         }
 
         viewToEnable.setVisibility(View.VISIBLE);
+        viewToEnable.setMovementMethod(new ScrollingMovementMethod());
 
         mEnableOk = true;
         mOk.setEnabled(true);
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java
index dbe32cc..0a4aa48 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java
@@ -22,6 +22,7 @@
 import android.content.DialogInterface;
 import android.os.Bundle;
 import android.text.Html;
+import android.text.method.ScrollingMovementMethod;
 import android.view.View;
 import android.widget.TextView;
 import androidx.annotation.NonNull;
@@ -94,6 +95,7 @@
             viewToEnable = dialogView.requireViewById(R.id.install_confirm_question);
         }
         viewToEnable.setVisibility(View.VISIBLE);
+        viewToEnable.setMovementMethod(new ScrollingMovementMethod());
 
         return mDialog;
     }
diff --git a/packages/SettingsLib/DataStore/Android.bp b/packages/SettingsLib/DataStore/Android.bp
new file mode 100644
index 0000000..868a4a5
--- /dev/null
+++ b/packages/SettingsLib/DataStore/Android.bp
@@ -0,0 +1,16 @@
+package {
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_library {
+    name: "SettingsLibDataStore",
+    defaults: [
+        "SettingsLintDefaults",
+    ],
+    srcs: ["src/**/*"],
+    static_libs: [
+        "androidx.annotation_annotation",
+        "androidx.collection_collection-ktx",
+        "guava",
+    ],
+}
diff --git a/packages/SettingsLib/DataStore/AndroidManifest.xml b/packages/SettingsLib/DataStore/AndroidManifest.xml
new file mode 100644
index 0000000..fb44627
--- /dev/null
+++ b/packages/SettingsLib/DataStore/AndroidManifest.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.settingslib.datastore">
+
+    <uses-sdk android:minSdkVersion="21" />
+</manifest>
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreContext.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreContext.kt
new file mode 100644
index 0000000..c6d6f77
--- /dev/null
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreContext.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.datastore
+
+import android.app.backup.BackupAgent
+import android.app.backup.BackupDataOutput
+import android.app.backup.BackupHelper
+import android.os.Build
+import android.os.ParcelFileDescriptor
+import androidx.annotation.RequiresApi
+
+/**
+ * Context for backup.
+ *
+ * @see BackupHelper.performBackup
+ * @see BackupDataOutput
+ */
+class BackupContext
+internal constructor(
+    /**
+     * An open, read-only file descriptor pointing to the last backup state provided by the
+     * application. May be null, in which case no prior state is being provided and the application
+     * should perform a full backup.
+     *
+     * TODO: the state should support marshall/unmarshall for incremental back up.
+     */
+    val oldState: ParcelFileDescriptor?,
+
+    /** An open, read/write BackupDataOutput pointing to the backup data destination. */
+    private val data: BackupDataOutput,
+
+    /**
+     * An open, read/write file descriptor pointing to an empty file. The application should record
+     * the final backup.
+     */
+    val newState: ParcelFileDescriptor,
+) {
+    /**
+     * The quota in bytes for the application's current backup operation.
+     *
+     * @see [BackupDataOutput.getQuota]
+     */
+    val quota: Long
+        @RequiresApi(Build.VERSION_CODES.O) get() = data.quota
+
+    /**
+     * Additional information about the backup transport.
+     *
+     * See [BackupAgent] for supported flags.
+     *
+     * @see [BackupDataOutput.getTransportFlags]
+     */
+    val transportFlags: Int
+        @RequiresApi(Build.VERSION_CODES.P) get() = data.transportFlags
+}
+
+/** Context for restore. */
+class RestoreContext(val key: String)
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreEntity.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreEntity.kt
new file mode 100644
index 0000000..6a7ef5a
--- /dev/null
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreEntity.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.datastore
+
+import android.app.backup.BackupDataOutput
+import android.app.backup.BackupHelper
+import androidx.annotation.BinderThread
+import java.io.IOException
+import java.io.InputStream
+import java.io.OutputStream
+
+/** Entity for back up and restore. */
+interface BackupRestoreEntity {
+    /**
+     * Key of the entity.
+     *
+     * The key string must be unique within the data set. Note that it is invalid if the first
+     * character is \uFF00 or higher.
+     *
+     * @see BackupDataOutput.writeEntityHeader
+     */
+    val key: String
+
+    /**
+     * Backs up the entity.
+     *
+     * @param backupContext context for backup
+     * @param outputStream output stream to back up data
+     * @return false if backup file is deleted, otherwise true
+     */
+    @BinderThread
+    @Throws(IOException::class)
+    fun backup(backupContext: BackupContext, outputStream: OutputStream): EntityBackupResult
+
+    /**
+     * Restores the entity.
+     *
+     * @param restoreContext context for restore
+     * @param inputStream An open input stream from which the backup data can be read.
+     * @see BackupHelper.restoreEntity
+     */
+    @BinderThread
+    @Throws(IOException::class)
+    fun restore(restoreContext: RestoreContext, inputStream: InputStream)
+}
+
+/** Result of the backup operation. */
+enum class EntityBackupResult {
+    /** Update the entity. */
+    UPDATE,
+    /** Leave the entity intact. */
+    INTACT,
+    /** Delete the entity. */
+    DELETE,
+}
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorage.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorage.kt
new file mode 100644
index 0000000..88d9dd6
--- /dev/null
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorage.kt
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.datastore
+
+import android.app.backup.BackupAgentHelper
+import android.app.backup.BackupDataInputStream
+import android.app.backup.BackupDataOutput
+import android.app.backup.BackupHelper
+import android.os.ParcelFileDescriptor
+import android.util.Log
+import com.google.common.io.ByteStreams
+import java.io.ByteArrayOutputStream
+import java.io.FilterInputStream
+import java.io.InputStream
+import java.io.OutputStream
+
+internal const val LOG_TAG = "BackupRestoreStorage"
+
+/**
+ * Storage with backup and restore support. Subclass must implement either [Observable] or
+ * [KeyedObservable] interface.
+ *
+ * The storage is identified by a unique string [name] and data set is split into entities
+ * ([BackupRestoreEntity]).
+ */
+abstract class BackupRestoreStorage : BackupHelper {
+    /**
+     * A unique string used to disambiguate the various storages within backup agent.
+     *
+     * It will be used as the `keyPrefix` of [BackupAgentHelper.addHelper].
+     */
+    abstract val name: String
+
+    private val entities: List<BackupRestoreEntity> by lazy { createBackupRestoreEntities() }
+
+    /** Entities to back up and restore. */
+    abstract fun createBackupRestoreEntities(): List<BackupRestoreEntity>
+
+    override fun performBackup(
+        oldState: ParcelFileDescriptor?,
+        data: BackupDataOutput,
+        newState: ParcelFileDescriptor,
+    ) {
+        val backupContext = BackupContext(oldState, data, newState)
+        if (!enableBackup(backupContext)) {
+            Log.i(LOG_TAG, "[$name] Backup disabled")
+            return
+        }
+        Log.i(LOG_TAG, "[$name] Backup start")
+        for (entity in entities) {
+            val key = entity.key
+            val outputStream = ByteArrayOutputStream()
+            val result =
+                try {
+                    entity.backup(backupContext, wrapBackupOutputStream(outputStream))
+                } catch (exception: Exception) {
+                    Log.e(LOG_TAG, "[$name] Fail to backup entity $key", exception)
+                    continue
+                }
+            when (result) {
+                EntityBackupResult.UPDATE -> {
+                    val payload = outputStream.toByteArray()
+                    val size = payload.size
+                    data.writeEntityHeader(key, size)
+                    data.writeEntityData(payload, size)
+                    Log.i(LOG_TAG, "[$name] Backup entity $key: $size bytes")
+                }
+                EntityBackupResult.INTACT -> {
+                    Log.i(LOG_TAG, "[$name] Backup entity $key intact")
+                }
+                EntityBackupResult.DELETE -> {
+                    data.writeEntityHeader(key, -1)
+                    Log.i(LOG_TAG, "[$name] Backup entity $key deleted")
+                }
+            }
+        }
+        Log.i(LOG_TAG, "[$name] Backup end")
+    }
+
+    /** Returns if backup is enabled. */
+    open fun enableBackup(backupContext: BackupContext): Boolean = true
+
+    fun wrapBackupOutputStream(outputStream: OutputStream): OutputStream {
+        return outputStream
+    }
+
+    override fun restoreEntity(data: BackupDataInputStream) {
+        val key = data.key
+        if (!enableRestore()) {
+            Log.i(LOG_TAG, "[$name] Restore disabled, ignore entity $key")
+            return
+        }
+        val entity = entities.firstOrNull { it.key == key }
+        if (entity == null) {
+            Log.w(LOG_TAG, "[$name] Cannot find handler for entity $key")
+            return
+        }
+        Log.i(LOG_TAG, "[$name] Restore $key: ${data.size()} bytes")
+        val restoreContext = RestoreContext(key)
+        try {
+            entity.restore(restoreContext, wrapRestoreInputStream(data))
+        } catch (exception: Exception) {
+            Log.e(LOG_TAG, "[$name] Fail to restore entity $key", exception)
+        }
+    }
+
+    /** Returns if restore is enabled. */
+    open fun enableRestore(): Boolean = true
+
+    fun wrapRestoreInputStream(inputStream: BackupDataInputStream): InputStream {
+        return LimitedNoCloseInputStream(inputStream)
+    }
+
+    override fun writeNewStateDescription(newState: ParcelFileDescriptor) {}
+}
+
+/**
+ * Wrapper of [BackupDataInputStream], limiting the number of bytes that can be read and make
+ * [close] no-op.
+ */
+class LimitedNoCloseInputStream(inputStream: BackupDataInputStream) :
+    FilterInputStream(ByteStreams.limit(inputStream, inputStream.size().toLong())) {
+    override fun close() {
+        // do not close original input stream
+    }
+}
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorageManager.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorageManager.kt
new file mode 100644
index 0000000..221e2e8
--- /dev/null
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorageManager.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.datastore
+
+import android.app.Application
+import android.app.backup.BackupAgentHelper
+import android.app.backup.BackupManager
+import android.content.Context
+import android.util.Log
+import com.google.common.util.concurrent.MoreExecutors
+import java.util.concurrent.ConcurrentHashMap
+
+/** Manager of [BackupRestoreStorage]. */
+class BackupRestoreStorageManager private constructor(private val application: Application) {
+    private val storages = ConcurrentHashMap<String, BackupRestoreStorage>()
+
+    private val executor = MoreExecutors.directExecutor()
+
+    private val observer = Observer { reason -> notifyBackupManager(null, reason) }
+
+    private val keyedObserver =
+        KeyedObserver<Any?> { key, reason -> notifyBackupManager(key, reason) }
+
+    private fun notifyBackupManager(key: Any?, reason: Int) {
+        // prefer not triggering backup immediately after restore
+        if (reason == ChangeReason.RESTORE) return
+        // TODO: log storage name
+        Log.d(LOG_TAG, "Notify BackupManager data changed for change: key=$key")
+        BackupManager.dataChanged(application.packageName)
+    }
+
+    /**
+     * Adds all the registered [BackupRestoreStorage] as the helpers of given [BackupAgentHelper].
+     *
+     * @see BackupAgentHelper.addHelper
+     */
+    fun addBackupAgentHelpers(backupAgentHelper: BackupAgentHelper) {
+        for ((keyPrefix, storage) in storages) {
+            backupAgentHelper.addHelper(keyPrefix, storage)
+        }
+    }
+
+    /**
+     * Callback when restore finished.
+     *
+     * The observers of the storages will be notified.
+     */
+    fun onRestoreFinished() {
+        for (storage in storages.values) {
+            storage.notifyRestoreFinished()
+        }
+    }
+
+    private fun BackupRestoreStorage.notifyRestoreFinished() {
+        when (this) {
+            is KeyedObservable<*> -> notifyChange(ChangeReason.RESTORE)
+            is Observable -> notifyChange(ChangeReason.RESTORE)
+        }
+    }
+
+    /**
+     * Adds a list of storages.
+     *
+     * The storage MUST implement [KeyedObservable] or [Observable].
+     */
+    fun add(vararg storages: BackupRestoreStorage) {
+        for (storage in storages) add(storage)
+    }
+
+    /**
+     * Adds a storage.
+     *
+     * The storage MUST implement [KeyedObservable] or [Observable].
+     */
+    fun add(storage: BackupRestoreStorage) {
+        val name = storage.name
+        val oldStorage = storages.put(name, storage)
+        if (oldStorage != null) {
+            throw IllegalStateException(
+                "Storage name '$name' conflicts:\n\told: $oldStorage\n\tnew: $storage"
+            )
+        }
+        storage.addObserver()
+    }
+
+    private fun BackupRestoreStorage.addObserver() {
+        when (this) {
+            is KeyedObservable<*> -> addObserver(keyedObserver, executor)
+            is Observable -> addObserver(observer, executor)
+            else ->
+                throw IllegalArgumentException(
+                    "$this does not implement either KeyedObservable or Observable"
+                )
+        }
+    }
+
+    /** Removes all the storages. */
+    fun removeAll() {
+        for ((name, _) in storages) remove(name)
+    }
+
+    /** Removes storage with given name. */
+    fun remove(name: String): BackupRestoreStorage? {
+        val storage = storages.remove(name)
+        storage?.removeObserver()
+        return storage
+    }
+
+    private fun BackupRestoreStorage.removeObserver() {
+        when (this) {
+            is KeyedObservable<*> -> removeObserver(keyedObserver)
+            is Observable -> removeObserver(observer)
+        }
+    }
+
+    /** Returns storage with given name. */
+    fun get(name: String): BackupRestoreStorage? = storages[name]
+
+    /** Returns storage with given name, exception is raised if not found. */
+    fun getOrThrow(name: String): BackupRestoreStorage = storages[name]!!
+
+    companion object {
+        @Volatile private var instance: BackupRestoreStorageManager? = null
+
+        /** Returns the singleton of manager. */
+        @JvmStatic
+        fun getInstance(context: Context): BackupRestoreStorageManager {
+            val result = instance
+            if (result != null) return result
+            synchronized(this) {
+                if (instance == null) {
+                    instance =
+                        BackupRestoreStorageManager(context.applicationContext as Application)
+                }
+            }
+            return instance!!
+        }
+    }
+}
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt
new file mode 100644
index 0000000..3ed4d46
--- /dev/null
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.datastore
+
+import androidx.annotation.AnyThread
+import androidx.annotation.GuardedBy
+import androidx.collection.MutableScatterMap
+import java.util.WeakHashMap
+import java.util.concurrent.Executor
+
+/**
+ * Callback to be informed of changes in [KeyedObservable] object.
+ *
+ * The observer is weakly referenced, a strong reference must be kept.
+ */
+fun interface KeyedObserver<in K> {
+    /**
+     * Called by [KeyedObservable] in the event of changes.
+     *
+     * This callback will run in the given [Executor] when observer is added.
+     *
+     * @param key key that has been changed
+     * @param reason the reason of change
+     * @see KeyedObservable.addObserver
+     */
+    fun onKeyChanged(key: K, @ChangeReason reason: Int)
+}
+
+/**
+ * A key-value observable object allows to observe change with [KeyedObserver].
+ *
+ * Notes:
+ * - The order in which observers will be notified is unspecified.
+ * - The observer is weakly referenced to avoid memory leaking, the call site must keep a strong
+ *   reference of the observer.
+ * - It is possible that the callback may be triggered even there is no real data change. For
+ *   example, when data restore/clear happens, it might be too complex to check if data is really
+ *   changed, thus all the registered observers are notified directly.
+ */
+@AnyThread
+interface KeyedObservable<K> {
+    /**
+     * Adds an observer for any key.
+     *
+     * The observer will be notified whenever a change happens. The [KeyedObserver.onKeyChanged]
+     * callback will be invoked with specific key that is modified. However, `null` key is passed in
+     * the cases that a bunch of keys are changed simultaneously (e.g. clear data, restore happens).
+     *
+     * @param observer observer to be notified
+     * @param executor executor to run the callback
+     */
+    fun addObserver(observer: KeyedObserver<K?>, executor: Executor)
+
+    /**
+     * Adds an observer on given key.
+     *
+     * The observer will be notified only when the given key is changed.
+     *
+     * @param key key to observe
+     * @param observer observer to be notified
+     * @param executor executor to run the callback
+     */
+    fun addObserver(key: K, observer: KeyedObserver<K>, executor: Executor)
+
+    /** Removes observer. */
+    fun removeObserver(observer: KeyedObserver<K?>)
+
+    /** Removes observer on given key. */
+    fun removeObserver(key: K, observer: KeyedObserver<K>)
+
+    /**
+     * Notifies all observers that a change occurs.
+     *
+     * All the any key and keyed observers are notified.
+     *
+     * @param reason reason of the change
+     */
+    fun notifyChange(@ChangeReason reason: Int)
+
+    /**
+     * Notifies observers that a change occurs on given key.
+     *
+     * The any key and specific key observers are notified.
+     *
+     * @param key key of the change
+     * @param reason reason of the change
+     */
+    fun notifyChange(key: K, @ChangeReason reason: Int)
+}
+
+/** A thread safe implementation of [KeyedObservable]. */
+class KeyedDataObservable<K> : KeyedObservable<K> {
+    // Instead of @GuardedBy("this"), guarded by itself because KeyedDataObservable object could be
+    // synchronized outside by the holder
+    @GuardedBy("itself") private val observers = WeakHashMap<KeyedObserver<K?>, Executor>()
+
+    @GuardedBy("itself")
+    private val keyedObservers = MutableScatterMap<K, WeakHashMap<KeyedObserver<K>, Executor>>()
+
+    override fun addObserver(observer: KeyedObserver<K?>, executor: Executor) {
+        val oldExecutor = synchronized(observers) { observers.put(observer, executor) }
+        if (oldExecutor != null && oldExecutor != executor) {
+            throw IllegalStateException("Add $observer twice, old=$oldExecutor, new=$executor")
+        }
+    }
+
+    override fun addObserver(key: K, observer: KeyedObserver<K>, executor: Executor) {
+        val oldExecutor =
+            synchronized(keyedObservers) {
+                keyedObservers.getOrPut(key) { WeakHashMap() }.put(observer, executor)
+            }
+        if (oldExecutor != null && oldExecutor != executor) {
+            throw IllegalStateException("Add $observer twice, old=$oldExecutor, new=$executor")
+        }
+    }
+
+    override fun removeObserver(observer: KeyedObserver<K?>) {
+        synchronized(observers) { observers.remove(observer) }
+    }
+
+    override fun removeObserver(key: K, observer: KeyedObserver<K>) {
+        synchronized(keyedObservers) {
+            val observers = keyedObservers[key]
+            if (observers?.remove(observer) != null && observers.isEmpty()) {
+                keyedObservers.remove(key)
+            }
+        }
+    }
+
+    override fun notifyChange(@ChangeReason reason: Int) {
+        // make a copy to avoid potential ConcurrentModificationException
+        val observers = synchronized(observers) { observers.entries.toTypedArray() }
+        val keyedObservers = synchronized(keyedObservers) { keyedObservers.copy() }
+        for (entry in observers) {
+            val observer = entry.key // avoid reference "entry"
+            entry.value.execute { observer.onKeyChanged(null, reason) }
+        }
+        for (pair in keyedObservers) {
+            val key = pair.first
+            for (entry in pair.second) {
+                val observer = entry.key // avoid reference "entry"
+                entry.value.execute { observer.onKeyChanged(key, reason) }
+            }
+        }
+    }
+
+    private fun MutableScatterMap<K, WeakHashMap<KeyedObserver<K>, Executor>>.copy():
+        List<Pair<K, Array<Map.Entry<KeyedObserver<K>, Executor>>>> {
+        val result = ArrayList<Pair<K, Array<Map.Entry<KeyedObserver<K>, Executor>>>>(size)
+        forEach { key, value -> result.add(Pair(key, value.entries.toTypedArray())) }
+        return result
+    }
+
+    override fun notifyChange(key: K, @ChangeReason reason: Int) {
+        // make a copy to avoid potential ConcurrentModificationException
+        val observers = synchronized(observers) { observers.entries.toTypedArray() }
+        val keyedObservers =
+            synchronized(keyedObservers) { keyedObservers[key]?.entries?.toTypedArray() }
+                ?: arrayOf()
+        for (entry in observers) {
+            val observer = entry.key // avoid reference "entry"
+            entry.value.execute { observer.onKeyChanged(key, reason) }
+        }
+        for (entry in keyedObservers) {
+            val observer = entry.key // avoid reference "entry"
+            entry.value.execute { observer.onKeyChanged(key, reason) }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKey.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/ObservableBackupRestoreStorage.kt
similarity index 66%
rename from packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKey.kt
rename to packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/ObservableBackupRestoreStorage.kt
index 87332ae..0e399c0 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKey.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/ObservableBackupRestoreStorage.kt
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.systemui.scene.shared.model
+package com.android.settingslib.datastore
 
 /**
- * Key for a transition. This can be used to specify which transition spec should be used when
- * starting the transition between two scenes.
+ * A [BackupRestoreStorage] that implements [Observable].
+ *
+ * This class provides the [Observable] implementations on top of [DataObservable] by delegation.
  */
-data class TransitionKey(
-    val debugName: String,
-    val identity: Any = Object(),
-)
+abstract class ObservableBackupRestoreStorage :
+    BackupRestoreStorage(), Observable by DataObservable()
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/Observer.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/Observer.kt
new file mode 100644
index 0000000..6d0ca669
--- /dev/null
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/Observer.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.datastore
+
+import androidx.annotation.AnyThread
+import androidx.annotation.GuardedBy
+import androidx.annotation.IntDef
+import java.util.WeakHashMap
+import java.util.concurrent.Executor
+
+/** The reason of a change. */
+@IntDef(
+    ChangeReason.UNKNOWN,
+    ChangeReason.UPDATE,
+    ChangeReason.DELETE,
+    ChangeReason.RESTORE,
+    ChangeReason.SYNC_ACROSS_PROFILES,
+)
+@Retention(AnnotationRetention.SOURCE)
+annotation class ChangeReason {
+    companion object {
+        /** Unknown reason of the change. */
+        const val UNKNOWN = 0
+        /** Data is updated. */
+        const val UPDATE = 1
+        /** Data is deleted. */
+        const val DELETE = 2
+        /** Data is restored from backup/restore framework. */
+        const val RESTORE = 3
+        /** Data is synced from another profile (e.g. personal profile to work profile). */
+        const val SYNC_ACROSS_PROFILES = 4
+    }
+}
+
+/**
+ * Callback to be informed of changes in [Observable] object.
+ *
+ * The observer is weakly referenced, a strong reference must be kept.
+ */
+fun interface Observer {
+    /**
+     * Called by [Observable] in the event of changes.
+     *
+     * This callback will run in the given [Executor] when observer is added.
+     *
+     * @param reason the reason of change
+     * @see [Observable.addObserver] for the notices.
+     */
+    fun onChanged(@ChangeReason reason: Int)
+}
+
+/** An observable object allows to observe change with [Observer]. */
+@AnyThread
+interface Observable {
+    /**
+     * Adds an observer.
+     *
+     * Notes:
+     * - The order in which observers will be notified is unspecified.
+     * - The observer is weakly referenced to avoid memory leaking, the call site must keep a strong
+     *   reference of the observer.
+     * - It is possible that the callback may be triggered even there is no real data change. For
+     *   example, when data restore/clear happens, it might be too complex to check if data is
+     *   really changed, thus all the registered observers are notified directly.
+     *
+     * @param observer observer to be notified
+     * @param executor executor to run the [Observer.onChanged] callback
+     */
+    fun addObserver(observer: Observer, executor: Executor)
+
+    /** Removes given observer. */
+    fun removeObserver(observer: Observer)
+
+    /**
+     * Notifies observers that a change occurs.
+     *
+     * @param reason reason of the change
+     */
+    fun notifyChange(@ChangeReason reason: Int)
+}
+
+/** A thread safe implementation of [Observable]. */
+class DataObservable : Observable {
+    // Instead of @GuardedBy("this"), guarded by itself because DataObservable object could be
+    // synchronized outside by the holder
+    @GuardedBy("itself") private val observers = WeakHashMap<Observer, Executor>()
+
+    override fun addObserver(observer: Observer, executor: Executor) {
+        val oldExecutor = synchronized(observers) { observers.put(observer, executor) }
+        if (oldExecutor != null && oldExecutor != executor) {
+            throw IllegalStateException("Add $observer twice, old=$oldExecutor, new=$executor")
+        }
+    }
+
+    override fun removeObserver(observer: Observer) {
+        synchronized(observers) { observers.remove(observer) }
+    }
+
+    override fun notifyChange(@ChangeReason reason: Int) {
+        // make a copy to avoid potential ConcurrentModificationException
+        val entries = synchronized(observers) { observers.entries.toTypedArray() }
+        for (entry in entries) {
+            val observer = entry.key // avoid reference "entry"
+            entry.value.execute { observer.onChanged(reason) }
+        }
+    }
+}
diff --git a/packages/SettingsLib/DataStore/tests/Android.bp b/packages/SettingsLib/DataStore/tests/Android.bp
new file mode 100644
index 0000000..8770dfa
--- /dev/null
+++ b/packages/SettingsLib/DataStore/tests/Android.bp
@@ -0,0 +1,24 @@
+package {
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_app {
+    name: "SettingsLibDataStoreShell",
+    platform_apis: true,
+}
+
+android_robolectric_test {
+    name: "SettingsLibDataStoreTest",
+    srcs: ["src/**/*"],
+    static_libs: [
+        "SettingsLibDataStore",
+        "androidx.test.ext.junit",
+        "guava",
+        "mockito-robolectric-prebuilt", // mockito deps order matters!
+        "mockito-kotlin2",
+    ],
+    java_resource_dirs: ["config"],
+    instrumentation_for: "SettingsLibDataStoreShell",
+    coverage_libs: ["SettingsLibDataStore"],
+    upstream: true,
+}
diff --git a/packages/SettingsLib/DataStore/tests/AndroidManifest.xml b/packages/SettingsLib/DataStore/tests/AndroidManifest.xml
new file mode 100644
index 0000000..ffc24e4
--- /dev/null
+++ b/packages/SettingsLib/DataStore/tests/AndroidManifest.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.settingslib.datastore.test">
+
+    <application android:debuggable="true" />
+</manifest>
diff --git a/packages/SettingsLib/DataStore/tests/config/robolectric.properties b/packages/SettingsLib/DataStore/tests/config/robolectric.properties
new file mode 100644
index 0000000..fab7251
--- /dev/null
+++ b/packages/SettingsLib/DataStore/tests/config/robolectric.properties
@@ -0,0 +1 @@
+sdk=NEWEST_SDK
diff --git a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/ObserverTest.kt b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/ObserverTest.kt
new file mode 100644
index 0000000..bb791dc
--- /dev/null
+++ b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/ObserverTest.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.datastore
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import com.google.common.util.concurrent.MoreExecutors
+import java.util.concurrent.Executor
+import java.util.concurrent.atomic.AtomicInteger
+import org.junit.Assert.assertThrows
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.any
+import org.mockito.kotlin.never
+import org.mockito.kotlin.reset
+import org.mockito.kotlin.verify
+
+@RunWith(AndroidJUnit4::class)
+class ObserverTest {
+    @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
+
+    @Mock private lateinit var observer1: Observer
+
+    @Mock private lateinit var observer2: Observer
+
+    @Mock private lateinit var executor: Executor
+
+    private val observable = DataObservable()
+
+    @Test
+    fun addObserver_sameExecutor() {
+        observable.addObserver(observer1, executor)
+        observable.addObserver(observer1, executor)
+    }
+
+    @Test
+    fun addObserver_differentExecutor() {
+        observable.addObserver(observer1, executor)
+        assertThrows(IllegalStateException::class.java) {
+            observable.addObserver(observer1, MoreExecutors.directExecutor())
+        }
+    }
+
+    @Test
+    fun addObserver_weaklyReferenced() {
+        val counter = AtomicInteger()
+        var observer: Observer? = Observer { counter.incrementAndGet() }
+        observable.addObserver(observer!!, MoreExecutors.directExecutor())
+
+        observable.notifyChange(ChangeReason.UPDATE)
+        assertThat(counter.get()).isEqualTo(1)
+
+        // trigger GC, the observer callback should not be invoked
+        @Suppress("unused")
+        observer = null
+        System.gc()
+        System.runFinalization()
+
+        observable.notifyChange(ChangeReason.UPDATE)
+        assertThat(counter.get()).isEqualTo(1)
+    }
+
+    @Test
+    fun addObserver_notifyObservers_removeObserver() {
+        observable.addObserver(observer1, MoreExecutors.directExecutor())
+        observable.addObserver(observer2, executor)
+
+        observable.notifyChange(ChangeReason.DELETE)
+
+        verify(observer1).onChanged(ChangeReason.DELETE)
+        verify(observer2, never()).onChanged(any())
+        verify(executor).execute(any())
+
+        reset(observer1, executor)
+        observable.removeObserver(observer2)
+
+        observable.notifyChange(ChangeReason.UPDATE)
+        verify(observer1).onChanged(ChangeReason.UPDATE)
+        verify(executor, never()).execute(any())
+    }
+
+    @Test
+    fun notifyChange_addObserverWithinCallback() {
+        // ConcurrentModificationException is raised if it is not implemented correctly
+        observable.addObserver(
+            { observable.addObserver(observer1, executor) },
+            MoreExecutors.directExecutor()
+        )
+        observable.notifyChange(ChangeReason.UPDATE)
+    }
+}
diff --git a/packages/SettingsLib/OWNERS b/packages/SettingsLib/OWNERS
index 5f5f1d5..5966c9f 100644
--- a/packages/SettingsLib/OWNERS
+++ b/packages/SettingsLib/OWNERS
@@ -5,6 +5,7 @@
 dsandler@android.com
 edgarwang@google.com
 evanlaird@google.com
+jiannan@google.com
 juliacr@google.com
 ykhung@google.com
 
diff --git a/packages/SettingsLib/Spa/build.gradle.kts b/packages/SettingsLib/Spa/build.gradle.kts
index 463e9be..335725c 100644
--- a/packages/SettingsLib/Spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/build.gradle.kts
@@ -29,7 +29,7 @@
 
 allprojects {
     extra["androidTop"] = androidTop
-    extra["jetpackComposeVersion"] = "1.7.0-alpha02"
+    extra["jetpackComposeVersion"] = "1.7.0-alpha03"
 }
 
 subprojects {
diff --git a/packages/SettingsLib/Spa/gradle/libs.versions.toml b/packages/SettingsLib/Spa/gradle/libs.versions.toml
index fe378c2..609a82e 100644
--- a/packages/SettingsLib/Spa/gradle/libs.versions.toml
+++ b/packages/SettingsLib/Spa/gradle/libs.versions.toml
@@ -16,7 +16,7 @@
 
 [versions]
 agp = "8.2.2"
-compose-compiler = "1.5.9"
+compose-compiler = "1.5.10"
 dexmaker-mockito = "2.28.3"
 jvm = "17"
 kotlin = "1.9.22"
diff --git a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_slider.png b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_slider.png
index a038779..e1f5c74 100644
--- a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_slider.png
+++ b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_slider.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_slider.png b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_slider.png
index 03db688..928e926 100644
--- a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_slider.png
+++ b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_slider.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_slider.png b/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_slider.png
index 1345c37..0521368 100644
--- a/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_slider.png
+++ b/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_slider.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts
index 2259bd74..a193a2f 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/spa/build.gradle.kts
@@ -57,7 +57,7 @@
     api("androidx.slice:slice-builders:1.1.0-alpha02")
     api("androidx.slice:slice-core:1.1.0-alpha02")
     api("androidx.slice:slice-view:1.1.0-alpha02")
-    api("androidx.compose.material3:material3:1.2.0")
+    api("androidx.compose.material3:material3:1.3.0-alpha01")
     api("androidx.compose.material:material-icons-extended:$jetpackComposeVersion")
     api("androidx.compose.runtime:runtime-livedata:$jetpackComposeVersion")
     api("androidx.compose.ui:ui-tooling-preview:$jetpackComposeVersion")
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt
index bb7e857..3acf075 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt
@@ -18,7 +18,6 @@
 
 import androidx.compose.foundation.clickable
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.vector.ImageVector
 import com.android.settingslib.spa.framework.common.EntryMacro
@@ -107,14 +106,9 @@
 ) {
     val onClickWithLog = wrapOnClickWithLog(model.onClick)
     val enabled = model.enabled()
-    val modifier = remember(enabled) {
-        if (onClickWithLog != null) {
-            Modifier.clickable(
-                enabled = enabled,
-                onClick = onClickWithLog
-            )
-        } else Modifier
-    }
+    val modifier = if (onClickWithLog != null) {
+        Modifier.clickable(enabled = enabled, onClick = onClickWithLog)
+    } else Modifier
     EntryHighlight {
         BasePreference(
             title = model.title,
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/RadioPreferences.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/RadioPreferences.kt
new file mode 100644
index 0000000..8300ce8
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/RadioPreferences.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.widget.preference
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.selection.selectable
+import androidx.compose.foundation.selection.selectableGroup
+import androidx.compose.material3.RadioButton
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.semantics.Role
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.widget.ui.CategoryTitle
+import com.android.settingslib.spa.widget.ui.SettingsListItem
+
+@Composable
+fun RadioPreferences(model: ListPreferenceModel) {
+    CategoryTitle(title = model.title)
+    Spacer(modifier = Modifier.width(SettingsDimension.itemDividerHeight))
+    Column(modifier = Modifier.selectableGroup()) {
+        for (option in model.options) {
+            Radio2(option, model.selectedId.intValue, model.enabled()) {
+                model.onIdSelected(it)
+            }
+        }
+    }
+}
+
+@Composable
+fun Radio2(
+    option: ListPreferenceOption,
+    selectedId: Int,
+    enabled: Boolean,
+    onIdSelected: (id: Int) -> Unit,
+) {
+    val selected = option.id == selectedId
+    Row(
+        modifier = Modifier
+            .fillMaxWidth()
+            .selectable(
+                selected = selected,
+                enabled = enabled,
+                onClick = { onIdSelected(option.id) },
+                role = Role.RadioButton,
+            )
+            .padding(SettingsDimension.dialogItemPadding),
+        verticalAlignment = Alignment.CenterVertically,
+    ) {
+        RadioButton(selected = selected, onClick = null, enabled = enabled)
+        Spacer(modifier = Modifier.width(SettingsDimension.itemDividerHeight))
+        SettingsListItem(text = option.text, enabled = enabled)
+    }
+}
\ No newline at end of file
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 4f61966..56534f4 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
@@ -180,7 +180,7 @@
      * @param colorTransitionFraction a `0.0` to `1.0` value that represents a color transition
      * percentage
      */
-    @Composable
+    @Stable
     fun containerColor(colorTransitionFraction: Float): Color {
         return lerp(
             containerColor,
@@ -519,7 +519,7 @@
                 0
             }
 
-        val layoutHeight = if (heightPx.isNaN()) 0 else heightPx.roundToInt()
+        val layoutHeight = if (heightPx > 0) heightPx.roundToInt() else 0
 
         layout(constraints.maxWidth, layoutHeight) {
             // Navigation icon
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt
index b4a6a0d..a59b95a 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt
@@ -66,6 +66,19 @@
 }
 
 @Composable
+fun SettingsListItem(text: String, enabled: Boolean = true) {
+    Text(
+        text = text,
+        modifier = Modifier
+            .alphaForEnabled(enabled)
+            .padding(vertical = SettingsDimension.paddingTiny),
+        color = MaterialTheme.colorScheme.onSurface,
+        style = MaterialTheme.typography.titleMedium,
+        overflow = TextOverflow.Ellipsis,
+    )
+}
+
+@Composable
 fun SettingsBody(
     body: String,
     maxLines: Int = Int.MAX_VALUE,
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/RadioPreferencesTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/RadioPreferencesTest.kt
new file mode 100644
index 0000000..2f98b02
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/RadioPreferencesTest.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.widget.preference
+
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.assertIsNotSelected
+import androidx.compose.ui.test.assertIsSelectable
+import androidx.compose.ui.test.assertIsSelected
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class RadioPreferencesTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    @Test
+    fun title_displayed() {
+        composeTestRule.setContent {
+            RadioPreferences(remember {
+                object : ListPreferenceModel {
+                    override val title = TITLE
+                    override val options = emptyList<ListPreferenceOption>()
+                    override val selectedId = mutableIntStateOf(0)
+                    override val onIdSelected: (Int) -> Unit = {}
+                }
+            })
+        }
+        composeTestRule.onNodeWithText(TITLE).assertIsDisplayed()
+    }
+
+    @Test
+    fun item_displayed() {
+        val selectedId = mutableIntStateOf(1)
+        composeTestRule.setContent {
+            RadioPreferences(remember {
+                object : ListPreferenceModel {
+                    override val title = TITLE
+                    override val options = listOf(
+                        ListPreferenceOption(id = 1, text = "A"),
+                        ListPreferenceOption(id = 2, text = "B"),
+                    )
+                    override val selectedId = selectedId
+                    override val onIdSelected = { id: Int -> selectedId.intValue = id }
+                }
+            })
+        }
+        composeTestRule.onNodeWithText("A").assertIsDisplayed()
+        composeTestRule.onNodeWithText("B").assertIsDisplayed()
+    }
+
+    @Test
+    fun item_selectable() {
+        val selectedId = mutableIntStateOf(1)
+        val enabledState = mutableStateOf(true)
+        composeTestRule.setContent {
+            RadioPreferences(remember {
+                object : ListPreferenceModel {
+                    override val title = TITLE
+                    override val enabled = { enabledState.value }
+                    override val options = listOf(
+                        ListPreferenceOption(id = 1, text = "A"),
+                        ListPreferenceOption(id = 2, text = "B"),
+                    )
+                    override val selectedId = selectedId
+                    override val onIdSelected = { id: Int -> selectedId.intValue = id }
+                }
+            })
+        }
+        composeTestRule.onNodeWithText("A").assertIsSelectable()
+        composeTestRule.onNodeWithText("B").assertIsSelectable()
+    }
+
+    @Test
+    fun item_single_selected() {
+        val selectedId = mutableIntStateOf(1)
+        val enabledState = mutableStateOf(true)
+        composeTestRule.setContent {
+            RadioPreferences(remember {
+                object : ListPreferenceModel {
+                    override val title = TITLE
+                    override val enabled = { enabledState.value }
+                    override val options = listOf(
+                        ListPreferenceOption(id = 1, text = "A"),
+                        ListPreferenceOption(id = 2, text = "B"),
+                    )
+                    override val selectedId = selectedId
+                    override val onIdSelected = { id: Int -> selectedId.intValue = id }
+                }
+            })
+        }
+        composeTestRule.onNodeWithText("B").assertIsSelectable()
+        composeTestRule.onNodeWithText("B").performClick()
+        composeTestRule.onNodeWithText("B").assertIsSelected()
+        composeTestRule.onNodeWithText("A").assertIsNotSelected()
+        composeTestRule.onNodeWithText("A").performClick()
+        composeTestRule.onNodeWithText("A").assertIsSelected()
+        composeTestRule.onNodeWithText("B").assertIsNotSelected()
+    }
+
+    @Test
+    fun select_itemDisabled() {
+        val selectedId = mutableIntStateOf(1)
+        val enabledState = mutableStateOf(true)
+        composeTestRule.setContent {
+            RadioPreferences(remember {
+                object : ListPreferenceModel {
+                    override val title = TITLE
+                    override val enabled = { enabledState.value }
+                    override val options = listOf(
+                        ListPreferenceOption(id = 1, text = "A"),
+                        ListPreferenceOption(id = 2, text = "B"),
+                    )
+                    override val selectedId = selectedId
+                    override val onIdSelected = { id: Int -> selectedId.intValue = id }
+                }
+            })
+        }
+        enabledState.value = false
+        composeTestRule.onNodeWithText("A").assertIsDisplayed().assertIsNotEnabled()
+        composeTestRule.onNodeWithText("B").assertIsDisplayed().assertIsNotEnabled()
+    }
+
+    private companion object {
+        const val TITLE = "Title"
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
index 988afd7..a395266 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
@@ -26,6 +26,7 @@
 import android.content.pm.PackageManager.ApplicationInfoFlags
 import android.content.pm.ResolveInfo
 import android.os.SystemProperties
+import android.util.Log
 import com.android.internal.R
 import com.android.settingslib.spaprivileged.framework.common.userManager
 import kotlinx.coroutines.async
@@ -85,19 +86,24 @@
         userId: Int,
         loadInstantApps: Boolean,
         matchAnyUserForAdmin: Boolean,
-    ): List<ApplicationInfo> = coroutineScope {
-        val hiddenSystemModulesDeferred = async { packageManager.getHiddenSystemModules() }
-        val hideWhenDisabledPackagesDeferred = async {
-            context.resources.getStringArray(R.array.config_hideWhenDisabled_packageNames)
-        }
-        val installedApplicationsAsUser =
-            getInstalledApplications(userId, matchAnyUserForAdmin)
+    ): List<ApplicationInfo> = try {
+        coroutineScope {
+            val hiddenSystemModulesDeferred = async { packageManager.getHiddenSystemModules() }
+            val hideWhenDisabledPackagesDeferred = async {
+                context.resources.getStringArray(R.array.config_hideWhenDisabled_packageNames)
+            }
+            val installedApplicationsAsUser =
+                getInstalledApplications(userId, matchAnyUserForAdmin)
 
-        val hiddenSystemModules = hiddenSystemModulesDeferred.await()
-        val hideWhenDisabledPackages = hideWhenDisabledPackagesDeferred.await()
-        installedApplicationsAsUser.filter { app ->
-            app.isInAppList(loadInstantApps, hiddenSystemModules, hideWhenDisabledPackages)
+            val hiddenSystemModules = hiddenSystemModulesDeferred.await()
+            val hideWhenDisabledPackages = hideWhenDisabledPackagesDeferred.await()
+            installedApplicationsAsUser.filter { app ->
+                app.isInAppList(loadInstantApps, hiddenSystemModules, hideWhenDisabledPackages)
+            }
         }
+    } catch (e: Exception) {
+        Log.e(TAG, "loadApps failed", e)
+        emptyList()
     }
 
     private suspend fun getInstalledApplications(
@@ -210,6 +216,8 @@
     }
 
     companion object {
+        private const val TAG = "AppListRepository"
+
         private fun ApplicationInfo.isInAppList(
             showInstantApps: Boolean,
             hiddenSystemModules: Set<String>,
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
index efd53a4..c60ce41 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
@@ -28,6 +28,8 @@
 import android.content.pm.ResolveInfo
 import android.content.pm.UserInfo
 import android.content.res.Resources
+import android.os.BadParcelableException
+import android.os.DeadObjectException
 import android.os.UserManager
 import android.platform.test.flag.junit.SetFlagsRule
 import androidx.test.core.app.ApplicationProvider
@@ -44,6 +46,7 @@
 import org.mockito.kotlin.argumentCaptor
 import org.mockito.kotlin.doAnswer
 import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.doThrow
 import org.mockito.kotlin.eq
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.spy
@@ -311,6 +314,19 @@
     }
 
     @Test
+    fun loadApps_hasException_returnEmptyList() = runTest {
+        packageManager.stub {
+            on {
+                getInstalledApplicationsAsUser(any<ApplicationInfoFlags>(), eq(ADMIN_USER_ID))
+            } doThrow BadParcelableException(DeadObjectException())
+        }
+
+        val appList = repository.loadApps(userId = ADMIN_USER_ID)
+
+        assertThat(appList).isEmpty()
+    }
+
+    @Test
     fun showSystemPredicate_showSystem() = runTest {
         val app = SYSTEM_APP
 
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index 6a1ee3a..54c5a14 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -43,4 +43,11 @@
   namespace: "pixel_cross_device_control"
   description: "Gates whether to enable LE audio private broadcast sharing via QR code"
   bug: "308368124"
-}
\ No newline at end of file
+}
+
+flag {
+  name: "enable_hide_exclusively_managed_bluetooth_device"
+  namespace: "dck_framework"
+  description: "Hide exclusively managed Bluetooth devices in BT settings menu."
+  bug: "324475542"
+}
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar.xml
new file mode 100644
index 0000000..d9a417f
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="14dp"
+        android:height="14dp"
+        android:viewportWidth="14.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M8.25,3L9.25,3A0.5,0.5 0,0 1,9.75 3.5L9.75,13.5A0.5,0.5 0,0 1,9.25 14L8.25,14A0.5,0.5 0,0 1,7.75 13.5L7.75,3.5A0.5,0.5 0,0 1,8.25 3z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M11.75,0L12.75,0A0.5,0.5 0,0 1,13.25 0.5L13.25,13.5A0.5,0.5 0,0 1,12.75 14L11.75,14A0.5,0.5 0,0 1,11.25 13.5L11.25,0.5A0.5,0.5 0,0 1,11.75 0z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M1.25,10L2.25,10A0.5,0.5 0,0 1,2.75 10.5L2.75,13.5A0.5,0.5 0,0 1,2.25 14L1.25,14A0.5,0.5 0,0 1,0.75 13.5L0.75,10.5A0.5,0.5 0,0 1,1.25 10z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M4.75,6.5L5.75,6.5A0.5,0.5 0,0 1,6.25 7L6.25,13.5A0.5,0.5 0,0 1,5.75 14L4.75,14A0.5,0.5 0,0 1,4.25 13.5L4.25,7A0.5,0.5 0,0 1,4.75 6.5z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar_error.xml
new file mode 100644
index 0000000..facc285
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar_error.xml
@@ -0,0 +1,28 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="15dp"
+        android:height="14dp"
+        android:viewportWidth="15.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M7,3.5C7,3.224 7.224,3 7.5,3H8.5C8.776,3 9,3.224 9,3.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V3.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M0,10.5C0,10.224 0.224,10 0.5,10H1.5C1.776,10 2,10.224 2,10.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V10.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M3.5,7C3.5,6.724 3.724,6.5 4,6.5H5C5.276,6.5 5.5,6.724 5.5,7V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V7Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M11,0C10.724,0 10.5,0.224 10.5,0.5V3H12.5V0.5C12.5,0.224 12.276,0 12,0H11Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M12.25,13C12.25,12.448 12.698,12 13.25,12C13.802,12 14.25,12.448 14.25,13C14.25,13.552 13.802,14 13.25,14C12.698,14 12.25,13.552 12.25,13Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M12.25,5C12.25,4.724 12.474,4.5 12.75,4.5H13.75C14.026,4.5 14.25,4.724 14.25,5V10C14.25,10.276 14.026,10.5 13.75,10.5H12.75C12.474,10.5 12.25,10.276 12.25,10V5Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar.xml
new file mode 100644
index 0000000..2c05a93
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar.xml
@@ -0,0 +1,41 @@
+<!--
+     Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="16dp"
+        android:height="14dp"
+        android:viewportWidth="16.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar_error.xml
new file mode 100644
index 0000000..328e45e
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar_error.xml
@@ -0,0 +1,32 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="18dp"
+        android:height="14dp"
+        android:viewportWidth="18.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M14,0.5C14,0.224 14.224,0 14.5,0H15.5C15.776,0 16,0.224 16,0.5V3H14V0.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M0.5,11C0.224,11 0,11.224 0,11.5V13.5C0,13.776 0.224,14 0.5,14H1.5C1.776,14 2,13.776 2,13.5V11.5C2,11.224 1.776,11 1.5,11H0.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M4,8C3.724,8 3.5,8.224 3.5,8.5V13.5C3.5,13.776 3.724,14 4,14H5C5.276,14 5.5,13.776 5.5,13.5V8.5C5.5,8.224 5.276,8 5,8H4Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar.xml
new file mode 100644
index 0000000..b9054ba
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="14dp"
+        android:height="14dp"
+        android:viewportWidth="14.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M8.25,3L9.25,3A0.5,0.5 0,0 1,9.75 3.5L9.75,13.5A0.5,0.5 0,0 1,9.25 14L8.25,14A0.5,0.5 0,0 1,7.75 13.5L7.75,3.5A0.5,0.5 0,0 1,8.25 3z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M11.75,0L12.75,0A0.5,0.5 0,0 1,13.25 0.5L13.25,13.5A0.5,0.5 0,0 1,12.75 14L11.75,14A0.5,0.5 0,0 1,11.25 13.5L11.25,0.5A0.5,0.5 0,0 1,11.75 0z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M1.25,10L2.25,10A0.5,0.5 0,0 1,2.75 10.5L2.75,13.5A0.5,0.5 0,0 1,2.25 14L1.25,14A0.5,0.5 0,0 1,0.75 13.5L0.75,10.5A0.5,0.5 0,0 1,1.25 10z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M4.75,6.5L5.75,6.5A0.5,0.5 0,0 1,6.25 7L6.25,13.5A0.5,0.5 0,0 1,5.75 14L4.75,14A0.5,0.5 0,0 1,4.25 13.5L4.25,7A0.5,0.5 0,0 1,4.75 6.5z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar_error.xml
new file mode 100644
index 0000000..03a9349
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar_error.xml
@@ -0,0 +1,27 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="15dp"
+        android:height="14dp"
+        android:viewportWidth="15.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M7,3.5C7,3.224 7.224,3 7.5,3H8.5C8.776,3 9,3.224 9,3.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V3.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M0,10.5C0,10.224 0.224,10 0.5,10H1.5C1.776,10 2,10.224 2,10.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V10.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M3.5,7C3.5,6.724 3.724,6.5 4,6.5H5C5.276,6.5 5.5,6.724 5.5,7V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V7Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M11,0C10.724,0 10.5,0.224 10.5,0.5V3H12.5V0.5C12.5,0.224 12.276,0 12,0H11Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M12.25,13C12.25,12.448 12.698,12 13.25,12C13.802,12 14.25,12.448 14.25,13C14.25,13.552 13.802,14 13.25,14C12.698,14 12.25,13.552 12.25,13Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M12.25,5C12.25,4.724 12.474,4.5 12.75,4.5H13.75C14.026,4.5 14.25,4.724 14.25,5V10C14.25,10.276 14.026,10.5 13.75,10.5H12.75C12.474,10.5 12.25,10.276 12.25,10V5Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar.xml
new file mode 100644
index 0000000..774e917
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="16dp"
+        android:height="14dp"
+        android:viewportWidth="16.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar_error.xml
new file mode 100644
index 0000000..343ec1b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar_error.xml
@@ -0,0 +1,31 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="18dp"
+        android:height="14dp"
+        android:viewportWidth="18.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M0,11.5C0,11.224 0.224,11 0.5,11H1.5C1.776,11 2,11.224 2,11.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V11.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M3.5,8.5C3.5,8.224 3.724,8 4,8H5C5.276,8 5.5,8.224 5.5,8.5V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V8.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.5,0C14.224,0 14,0.224 14,0.5V3H16V0.5C16,0.224 15.776,0 15.5,0H14.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar.xml
new file mode 100644
index 0000000..b699203
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="14dp"
+        android:height="14dp"
+        android:viewportWidth="14.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M8.25,3L9.25,3A0.5,0.5 0,0 1,9.75 3.5L9.75,13.5A0.5,0.5 0,0 1,9.25 14L8.25,14A0.5,0.5 0,0 1,7.75 13.5L7.75,3.5A0.5,0.5 0,0 1,8.25 3z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M11.75,0L12.75,0A0.5,0.5 0,0 1,13.25 0.5L13.25,13.5A0.5,0.5 0,0 1,12.75 14L11.75,14A0.5,0.5 0,0 1,11.25 13.5L11.25,0.5A0.5,0.5 0,0 1,11.75 0z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M1.25,10L2.25,10A0.5,0.5 0,0 1,2.75 10.5L2.75,13.5A0.5,0.5 0,0 1,2.25 14L1.25,14A0.5,0.5 0,0 1,0.75 13.5L0.75,10.5A0.5,0.5 0,0 1,1.25 10z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M4.75,6.5L5.75,6.5A0.5,0.5 0,0 1,6.25 7L6.25,13.5A0.5,0.5 0,0 1,5.75 14L4.75,14A0.5,0.5 0,0 1,4.25 13.5L4.25,7A0.5,0.5 0,0 1,4.75 6.5z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar_error.xml
new file mode 100644
index 0000000..ba8649b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar_error.xml
@@ -0,0 +1,26 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="15dp"
+        android:height="14dp"
+        android:viewportWidth="15.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M7,3.5C7,3.224 7.224,3 7.5,3H8.5C8.776,3 9,3.224 9,3.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V3.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M0,10.5C0,10.224 0.224,10 0.5,10H1.5C1.776,10 2,10.224 2,10.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V10.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M3.5,7C3.5,6.724 3.724,6.5 4,6.5H5C5.276,6.5 5.5,6.724 5.5,7V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V7Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M11,0C10.724,0 10.5,0.224 10.5,0.5V3H12.5V0.5C12.5,0.224 12.276,0 12,0H11Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M12.25,13C12.25,12.448 12.698,12 13.25,12C13.802,12 14.25,12.448 14.25,13C14.25,13.552 13.802,14 13.25,14C12.698,14 12.25,13.552 12.25,13Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M12.25,5C12.25,4.724 12.474,4.5 12.75,4.5H13.75C14.026,4.5 14.25,4.724 14.25,5V10C14.25,10.276 14.026,10.5 13.75,10.5H12.75C12.474,10.5 12.25,10.276 12.25,10V5Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar.xml
new file mode 100644
index 0000000..43fa734
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="16dp"
+        android:height="14dp"
+        android:viewportWidth="16.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar_error.xml
new file mode 100644
index 0000000..6309e17
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar_error.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="18dp"
+        android:height="14dp"
+        android:viewportWidth="18.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M0,11.5C0,11.224 0.224,11 0.5,11H1.5C1.776,11 2,11.224 2,11.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V11.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M3.5,8.5C3.5,8.224 3.724,8 4,8H5C5.276,8 5.5,8.224 5.5,8.5V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V8.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.5,0C14.224,0 14,0.224 14,0.5V3H16V0.5C16,0.224 15.776,0 15.5,0H14.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar.xml
new file mode 100644
index 0000000..6a218b3
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="14dp"
+        android:height="14dp"
+        android:viewportWidth="14.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M8.25,3L9.25,3A0.5,0.5 0,0 1,9.75 3.5L9.75,13.5A0.5,0.5 0,0 1,9.25 14L8.25,14A0.5,0.5 0,0 1,7.75 13.5L7.75,3.5A0.5,0.5 0,0 1,8.25 3z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M11.75,0L12.75,0A0.5,0.5 0,0 1,13.25 0.5L13.25,13.5A0.5,0.5 0,0 1,12.75 14L11.75,14A0.5,0.5 0,0 1,11.25 13.5L11.25,0.5A0.5,0.5 0,0 1,11.75 0z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M1.25,10L2.25,10A0.5,0.5 0,0 1,2.75 10.5L2.75,13.5A0.5,0.5 0,0 1,2.25 14L1.25,14A0.5,0.5 0,0 1,0.75 13.5L0.75,10.5A0.5,0.5 0,0 1,1.25 10z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M4.75,6.5L5.75,6.5A0.5,0.5 0,0 1,6.25 7L6.25,13.5A0.5,0.5 0,0 1,5.75 14L4.75,14A0.5,0.5 0,0 1,4.25 13.5L4.25,7A0.5,0.5 0,0 1,4.75 6.5z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar_error.xml
new file mode 100644
index 0000000..27433c7
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar_error.xml
@@ -0,0 +1,25 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="15dp"
+        android:height="14dp"
+        android:viewportWidth="15.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M7,3.5C7,3.224 7.224,3 7.5,3H8.5C8.776,3 9,3.224 9,3.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V3.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M0,10.5C0,10.224 0.224,10 0.5,10H1.5C1.776,10 2,10.224 2,10.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V10.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M3.5,7C3.5,6.724 3.724,6.5 4,6.5H5C5.276,6.5 5.5,6.724 5.5,7V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V7Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M11,0C10.724,0 10.5,0.224 10.5,0.5V3H12.5V0.5C12.5,0.224 12.276,0 12,0H11Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M12.25,13C12.25,12.448 12.698,12 13.25,12C13.802,12 14.25,12.448 14.25,13C14.25,13.552 13.802,14 13.25,14C12.698,14 12.25,13.552 12.25,13Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M12.25,5C12.25,4.724 12.474,4.5 12.75,4.5H13.75C14.026,4.5 14.25,4.724 14.25,5V10C14.25,10.276 14.026,10.5 13.75,10.5H12.75C12.474,10.5 12.25,10.276 12.25,10V5Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar.xml
new file mode 100644
index 0000000..158ae01
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="16dp"
+        android:height="14dp"
+        android:viewportWidth="16.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar_error.xml
new file mode 100644
index 0000000..e0517cf
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar_error.xml
@@ -0,0 +1,29 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="18dp"
+        android:height="14dp"
+        android:viewportWidth="18.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M0,11.5C0,11.224 0.224,11 0.5,11H1.5C1.776,11 2,11.224 2,11.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V11.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M3.5,8.5C3.5,8.224 3.724,8 4,8H5C5.276,8 5.5,8.224 5.5,8.5V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V8.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.5,0C14.224,0 14,0.224 14,0.5V3H16V0.5C16,0.224 15.776,0 15.5,0H14.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar.xml
new file mode 100644
index 0000000..1ebd396
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="14dp"
+        android:height="14dp"
+        android:viewportWidth="14.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M8.25,3L9.25,3A0.5,0.5 0,0 1,9.75 3.5L9.75,13.5A0.5,0.5 0,0 1,9.25 14L8.25,14A0.5,0.5 0,0 1,7.75 13.5L7.75,3.5A0.5,0.5 0,0 1,8.25 3z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M11.75,0L12.75,0A0.5,0.5 0,0 1,13.25 0.5L13.25,13.5A0.5,0.5 0,0 1,12.75 14L11.75,14A0.5,0.5 0,0 1,11.25 13.5L11.25,0.5A0.5,0.5 0,0 1,11.75 0z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M1.25,10L2.25,10A0.5,0.5 0,0 1,2.75 10.5L2.75,13.5A0.5,0.5 0,0 1,2.25 14L1.25,14A0.5,0.5 0,0 1,0.75 13.5L0.75,10.5A0.5,0.5 0,0 1,1.25 10z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M4.75,6.5L5.75,6.5A0.5,0.5 0,0 1,6.25 7L6.25,13.5A0.5,0.5 0,0 1,5.75 14L4.75,14A0.5,0.5 0,0 1,4.25 13.5L4.25,7A0.5,0.5 0,0 1,4.75 6.5z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar_error.xml
new file mode 100644
index 0000000..4473c29
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar_error.xml
@@ -0,0 +1,24 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="15dp"
+        android:height="14dp"
+        android:viewportWidth="15.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M7,3.5C7,3.224 7.224,3 7.5,3H8.5C8.776,3 9,3.224 9,3.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V3.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M0,10.5C0,10.224 0.224,10 0.5,10H1.5C1.776,10 2,10.224 2,10.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V10.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M3.5,7C3.5,6.724 3.724,6.5 4,6.5H5C5.276,6.5 5.5,6.724 5.5,7V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V7Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M11,0C10.724,0 10.5,0.224 10.5,0.5V3H12.5V0.5C12.5,0.224 12.276,0 12,0H11Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M12.25,13C12.25,12.448 12.698,12 13.25,12C13.802,12 14.25,12.448 14.25,13C14.25,13.552 13.802,14 13.25,14C12.698,14 12.25,13.552 12.25,13Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M12.25,5C12.25,4.724 12.474,4.5 12.75,4.5H13.75C14.026,4.5 14.25,4.724 14.25,5V10C14.25,10.276 14.026,10.5 13.75,10.5H12.75C12.474,10.5 12.25,10.276 12.25,10V5Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar.xml
new file mode 100644
index 0000000..1ed6ac8
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="16dp"
+        android:height="14dp"
+        android:viewportWidth="16.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar_error.xml
new file mode 100644
index 0000000..703e3ac
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar_error.xml
@@ -0,0 +1,28 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="18dp"
+        android:height="14dp"
+        android:viewportWidth="18.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M0,11.5C0,11.224 0.224,11 0.5,11H1.5C1.776,11 2,11.224 2,11.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V11.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M3.5,8.5C3.5,8.224 3.724,8 4,8H5C5.276,8 5.5,8.224 5.5,8.5V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V8.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.5,0C14.224,0 14,0.224 14,0.5V3H16V0.5C16,0.224 15.776,0 15.5,0H14.5Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar.xml
new file mode 100644
index 0000000..420ffb6
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="16dp"
+        android:height="14dp"
+        android:viewportWidth="16.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar_error.xml
new file mode 100644
index 0000000..e63ca77
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar_error.xml
@@ -0,0 +1,27 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="18dp"
+        android:height="14dp"
+        android:viewportWidth="18.0"
+        android:viewportHeight="14.0">
+    <path
+        android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M0,11.5C0,11.224 0.224,11 0.5,11H1.5C1.776,11 2,11.224 2,11.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V11.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M3.5,8.5C3.5,8.224 3.724,8 4,8H5C5.276,8 5.5,8.224 5.5,8.5V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V8.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.5,0C14.224,0 14,0.224 14,0.5V3H16V0.5C16,0.224 15.776,0 15.5,0H14.5Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_mobile_level_list.xml b/packages/SettingsLib/res/drawable/ic_mobile_level_list.xml
new file mode 100644
index 0000000..6ec6793
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_mobile_level_list.xml
@@ -0,0 +1,46 @@
+<?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
+  -->
+
+<!-- In order to pack the 0-4 and 0-5 ranges into a single element, we use a range offset. See
+SignalDrawable.java for usage. -->
+<level-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:minLevel="0" android:maxLevel="0" android:drawable="@drawable/ic_mobile_0_4_bar" />
+    <item android:minLevel="1" android:maxLevel="1" android:drawable="@drawable/ic_mobile_1_4_bar" />
+    <item android:minLevel="2" android:maxLevel="2" android:drawable="@drawable/ic_mobile_2_4_bar" />
+    <item android:minLevel="3" android:maxLevel="3" android:drawable="@drawable/ic_mobile_3_4_bar" />
+    <item android:minLevel="4" android:maxLevel="4" android:drawable="@drawable/ic_mobile_4_4_bar" />
+    <item android:minLevel="10" android:maxLevel="10" android:drawable="@drawable/ic_mobile_0_5_bar" />
+    <item android:minLevel="11" android:maxLevel="11" android:drawable="@drawable/ic_mobile_1_5_bar" />
+    <item android:minLevel="12" android:maxLevel="12" android:drawable="@drawable/ic_mobile_2_5_bar" />
+    <item android:minLevel="13" android:maxLevel="13" android:drawable="@drawable/ic_mobile_3_5_bar" />
+    <item android:minLevel="14" android:maxLevel="14" android:drawable="@drawable/ic_mobile_4_5_bar" />
+    <item android:minLevel="15" android:maxLevel="15" android:drawable="@drawable/ic_mobile_5_5_bar" />
+    
+    <!-- Error states, so we don't have to draw them manually anymore -->
+    <item android:minLevel="20" android:maxLevel="20" android:drawable="@drawable/ic_mobile_0_4_bar_error" />
+    <item android:minLevel="21" android:maxLevel="21" android:drawable="@drawable/ic_mobile_1_4_bar_error" />
+    <item android:minLevel="22" android:maxLevel="22" android:drawable="@drawable/ic_mobile_2_4_bar_error" />
+    <item android:minLevel="23" android:maxLevel="23" android:drawable="@drawable/ic_mobile_3_4_bar_error" />
+    <item android:minLevel="24" android:maxLevel="24" android:drawable="@drawable/ic_mobile_4_4_bar_error" />
+
+    <item android:minLevel="30" android:maxLevel="30" android:drawable="@drawable/ic_mobile_0_5_bar_error" />
+    <item android:minLevel="31" android:maxLevel="31" android:drawable="@drawable/ic_mobile_1_5_bar_error" />
+    <item android:minLevel="32" android:maxLevel="32" android:drawable="@drawable/ic_mobile_2_5_bar_error" />
+    <item android:minLevel="33" android:maxLevel="33" android:drawable="@drawable/ic_mobile_3_5_bar_error" />
+    <item android:minLevel="34" android:maxLevel="34" android:drawable="@drawable/ic_mobile_4_5_bar_error" />
+    <item android:minLevel="35" android:maxLevel="35" android:drawable="@drawable/ic_mobile_5_5_bar_error" />
+</level-list>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_0.xml b/packages/SettingsLib/res/drawable/ic_wifi_0.xml
new file mode 100644
index 0000000..8ff6554
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_wifi_0.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="18dp"
+        android:height="13dp"
+        android:viewportWidth="18.0"
+        android:viewportHeight="13.0">
+    <path
+        android:pathData="M0.523,3.314C0.32,3.502 0.32,3.819 0.516,4.015L1.223,4.722C1.418,4.917 1.734,4.916 1.938,4.73C5.936,1.09 12.066,1.09 16.064,4.73C16.268,4.916 16.584,4.917 16.779,4.722L17.486,4.015C17.682,3.819 17.682,3.502 17.479,3.314C12.698,-1.105 5.304,-1.105 0.523,3.314Z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M15.011,6.49C15.207,6.294 15.207,5.976 15.002,5.792C11.592,2.736 6.411,2.736 3,5.792C2.795,5.976 2.795,6.294 2.991,6.49L3.698,7.197C3.893,7.392 4.209,7.39 4.417,7.209C7.042,4.93 10.96,4.93 13.585,7.209C13.793,7.39 14.109,7.392 14.304,7.197L15.011,6.49Z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M5.465,8.964C5.27,8.769 5.269,8.45 5.481,8.273C7.515,6.576 10.487,6.576 12.521,8.273C12.733,8.45 12.732,8.769 12.537,8.964L11.83,9.672C11.634,9.867 11.319,9.863 11.099,9.698C9.859,8.767 8.143,8.767 6.904,9.698C6.683,9.863 6.368,9.867 6.173,9.672L5.465,8.964Z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M10.062,11.439C10.257,11.244 10.259,10.92 10.022,10.779C9.395,10.407 8.608,10.407 7.98,10.779C7.743,10.92 7.745,11.244 7.94,11.439L8.647,12.146C8.843,12.342 9.159,12.342 9.355,12.146L10.062,11.439Z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_0_error.xml b/packages/SettingsLib/res/drawable/ic_wifi_0_error.xml
new file mode 100644
index 0000000..db31b9d
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_wifi_0_error.xml
@@ -0,0 +1,28 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="17dp"
+        android:height="13dp"
+        android:viewportWidth="17.0"
+        android:viewportHeight="13.0">
+    <path
+        android:pathData="M0.146,4.015C-0.05,3.819 -0.05,3.502 0.153,3.314C4.002,-0.244 9.545,-0.937 14.055,1.234C13.339,1.449 12.792,2.053 12.66,2.801C8.998,1.281 4.65,1.924 1.568,4.73C1.364,4.916 1.048,4.917 0.853,4.722L0.146,4.015Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M12.63,4.435C9.406,2.836 5.424,3.288 2.63,5.792C2.424,5.976 2.425,6.294 2.621,6.49L3.328,7.197C3.523,7.392 3.839,7.39 4.047,7.209C6.484,5.094 10.033,4.942 12.63,6.753V4.435Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M5.095,8.964C4.9,8.769 4.899,8.45 5.111,8.273C7.145,6.576 10.117,6.576 12.151,8.273C12.363,8.45 12.362,8.769 12.166,8.964L11.459,9.672C11.264,9.867 10.949,9.863 10.728,9.698C9.489,8.767 7.773,8.767 6.533,9.698C6.313,9.863 5.998,9.867 5.802,9.672L5.095,8.964Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M9.652,10.779C9.889,10.92 9.887,11.244 9.692,11.439L8.984,12.146C8.789,12.342 8.473,12.342 8.277,12.146L7.57,11.439C7.375,11.244 7.373,10.92 7.61,10.779C8.237,10.407 9.024,10.407 9.652,10.779Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.63,11.15C14.63,10.598 15.078,10.15 15.63,10.15C16.182,10.15 16.63,10.598 16.63,11.15C16.63,11.703 16.182,12.15 15.63,12.15C15.078,12.15 14.63,11.703 14.63,11.15Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.63,3.15C14.63,2.874 14.854,2.65 15.13,2.65H16.13C16.406,2.65 16.63,2.874 16.63,3.15V8.15C16.63,8.427 16.406,8.65 16.13,8.65H15.13C14.854,8.65 14.63,8.427 14.63,8.15V3.15Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_1.xml b/packages/SettingsLib/res/drawable/ic_wifi_1.xml
new file mode 100644
index 0000000..e170f1d
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_wifi_1.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="18dp"
+        android:height="13dp"
+        android:viewportWidth="18.0"
+        android:viewportHeight="13.0">
+    <path
+        android:pathData="M0.523,3.314C0.32,3.502 0.32,3.819 0.516,4.015L1.223,4.722C1.418,4.917 1.734,4.916 1.938,4.73C5.936,1.09 12.066,1.09 16.064,4.73C16.268,4.916 16.584,4.917 16.779,4.722L17.486,4.015C17.682,3.819 17.682,3.502 17.479,3.314C12.698,-1.105 5.304,-1.105 0.523,3.314Z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M15.011,6.49C15.207,6.294 15.207,5.976 15.002,5.792C11.592,2.736 6.411,2.736 3,5.792C2.795,5.976 2.795,6.294 2.991,6.49L3.698,7.197C3.893,7.392 4.209,7.39 4.417,7.209C7.042,4.93 10.96,4.93 13.585,7.209C13.793,7.39 14.109,7.392 14.304,7.197L15.011,6.49Z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M5.465,8.964C5.27,8.769 5.269,8.45 5.481,8.273C7.515,6.576 10.487,6.576 12.521,8.273C12.733,8.45 12.732,8.769 12.537,8.964L11.83,9.672C11.634,9.867 11.319,9.863 11.099,9.698C9.859,8.767 8.143,8.767 6.904,9.698C6.683,9.863 6.368,9.867 6.173,9.672L5.465,8.964Z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M10.062,11.439C10.257,11.244 10.259,10.92 10.022,10.779C9.395,10.407 8.608,10.407 7.98,10.779C7.743,10.92 7.745,11.244 7.94,11.439L8.647,12.146C8.843,12.342 9.159,12.342 9.355,12.146L10.062,11.439Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_1_error.xml b/packages/SettingsLib/res/drawable/ic_wifi_1_error.xml
new file mode 100644
index 0000000..a4d6a5c
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_wifi_1_error.xml
@@ -0,0 +1,27 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="17dp"
+        android:height="13dp"
+        android:viewportWidth="17.0"
+        android:viewportHeight="13.0">
+    <path
+        android:pathData="M0.146,4.015C-0.05,3.819 -0.05,3.502 0.153,3.314C4.002,-0.244 9.545,-0.937 14.055,1.234C13.339,1.449 12.792,2.053 12.66,2.801C8.998,1.281 4.65,1.924 1.568,4.73C1.364,4.916 1.048,4.917 0.853,4.722L0.146,4.015Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M12.63,4.435C9.406,2.836 5.424,3.288 2.63,5.792C2.424,5.976 2.425,6.294 2.621,6.49L3.328,7.197C3.523,7.392 3.839,7.39 4.047,7.209C6.484,5.094 10.033,4.942 12.63,6.753V4.435Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M5.095,8.964C4.9,8.769 4.899,8.45 5.111,8.273C7.145,6.576 10.117,6.576 12.151,8.273C12.363,8.45 12.362,8.769 12.166,8.964L11.459,9.672C11.264,9.867 10.949,9.863 10.728,9.698C9.489,8.767 7.773,8.767 6.533,9.698C6.313,9.863 5.998,9.867 5.802,9.672L5.095,8.964Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M9.652,10.779C9.889,10.92 9.887,11.244 9.692,11.439L8.984,12.146C8.789,12.342 8.473,12.342 8.277,12.146L7.57,11.439C7.375,11.244 7.373,10.92 7.61,10.779C8.237,10.407 9.024,10.407 9.652,10.779Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.63,11.15C14.63,10.598 15.078,10.15 15.63,10.15C16.182,10.15 16.63,10.598 16.63,11.15C16.63,11.703 16.182,12.15 15.63,12.15C15.078,12.15 14.63,11.703 14.63,11.15Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.63,3.15C14.63,2.874 14.854,2.65 15.13,2.65H16.13C16.406,2.65 16.63,2.874 16.63,3.15V8.15C16.63,8.427 16.406,8.65 16.13,8.65H15.13C14.854,8.65 14.63,8.427 14.63,8.15V3.15Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_2.xml b/packages/SettingsLib/res/drawable/ic_wifi_2.xml
new file mode 100644
index 0000000..fc62267
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_wifi_2.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="18dp"
+        android:height="13dp"
+        android:viewportWidth="18.0"
+        android:viewportHeight="13.0">
+    <path
+        android:pathData="M0.523,3.314C0.32,3.502 0.32,3.819 0.516,4.015L1.223,4.722C1.418,4.917 1.734,4.916 1.938,4.73C5.936,1.09 12.066,1.09 16.064,4.73C16.268,4.916 16.584,4.917 16.779,4.722L17.486,4.015C17.682,3.819 17.682,3.502 17.479,3.314C12.698,-1.105 5.304,-1.105 0.523,3.314Z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M15.011,6.49C15.207,6.294 15.207,5.976 15.002,5.792C11.592,2.736 6.411,2.736 3,5.792C2.795,5.976 2.795,6.294 2.991,6.49L3.698,7.197C3.893,7.392 4.209,7.39 4.417,7.209C7.042,4.93 10.96,4.93 13.585,7.209C13.793,7.39 14.109,7.392 14.304,7.197L15.011,6.49Z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M5.465,8.964C5.27,8.769 5.269,8.45 5.481,8.273C7.515,6.576 10.487,6.576 12.521,8.273C12.733,8.45 12.732,8.769 12.537,8.964L11.83,9.672C11.634,9.867 11.319,9.863 11.099,9.698C9.859,8.767 8.143,8.767 6.904,9.698C6.683,9.863 6.368,9.867 6.173,9.672L5.465,8.964Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M10.062,11.439C10.257,11.244 10.259,10.92 10.022,10.779C9.395,10.407 8.608,10.407 7.98,10.779C7.743,10.92 7.745,11.244 7.94,11.439L8.647,12.146C8.843,12.342 9.159,12.342 9.355,12.146L10.062,11.439Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_2_error.xml b/packages/SettingsLib/res/drawable/ic_wifi_2_error.xml
new file mode 100644
index 0000000..65f40ef
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_wifi_2_error.xml
@@ -0,0 +1,26 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="17dp"
+        android:height="13dp"
+        android:viewportWidth="17.0"
+        android:viewportHeight="13.0">
+    <path
+        android:pathData="M0.146,4.015C-0.05,3.819 -0.05,3.502 0.153,3.314C4.002,-0.244 9.545,-0.937 14.055,1.234C13.339,1.449 12.792,2.053 12.66,2.801C8.998,1.281 4.65,1.924 1.568,4.73C1.364,4.916 1.048,4.917 0.853,4.722L0.146,4.015Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M12.63,4.435C9.406,2.836 5.424,3.288 2.63,5.792C2.424,5.976 2.425,6.294 2.621,6.49L3.328,7.197C3.523,7.392 3.839,7.39 4.047,7.209C6.484,5.094 10.033,4.942 12.63,6.753V4.435Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M5.095,8.964C4.9,8.769 4.899,8.45 5.111,8.273C7.145,6.576 10.117,6.576 12.151,8.273C12.363,8.45 12.362,8.769 12.166,8.964L11.459,9.672C11.264,9.867 10.949,9.863 10.728,9.698C9.489,8.767 7.773,8.767 6.533,9.698C6.313,9.863 5.998,9.867 5.802,9.672L5.095,8.964Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M9.652,10.779C9.889,10.92 9.887,11.244 9.692,11.439L8.984,12.146C8.789,12.342 8.473,12.342 8.277,12.146L7.57,11.439C7.375,11.244 7.373,10.92 7.61,10.779C8.237,10.407 9.024,10.407 9.652,10.779Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.63,11.15C14.63,10.598 15.078,10.15 15.63,10.15C16.182,10.15 16.63,10.598 16.63,11.15C16.63,11.703 16.182,12.15 15.63,12.15C15.078,12.15 14.63,11.703 14.63,11.15Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.63,3.15C14.63,2.874 14.854,2.65 15.13,2.65H16.13C16.406,2.65 16.63,2.874 16.63,3.15V8.15C16.63,8.427 16.406,8.65 16.13,8.65H15.13C14.854,8.65 14.63,8.427 14.63,8.15V3.15Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_3.xml b/packages/SettingsLib/res/drawable/ic_wifi_3.xml
new file mode 100644
index 0000000..9079daf
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_wifi_3.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="18dp"
+        android:height="13dp"
+        android:viewportWidth="18.0"
+        android:viewportHeight="13.0">
+    <path
+        android:pathData="M0.523,3.314C0.32,3.502 0.32,3.819 0.516,4.015L1.223,4.722C1.418,4.917 1.734,4.916 1.938,4.73C5.936,1.09 12.066,1.09 16.064,4.73C16.268,4.916 16.584,4.917 16.779,4.722L17.486,4.015C17.682,3.819 17.682,3.502 17.479,3.314C12.698,-1.105 5.304,-1.105 0.523,3.314Z"
+        android:fillAlpha="0.24"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M15.011,6.49C15.207,6.294 15.207,5.976 15.002,5.792C11.592,2.736 6.411,2.736 3,5.792C2.795,5.976 2.795,6.294 2.991,6.49L3.698,7.197C3.893,7.392 4.209,7.39 4.417,7.209C7.042,4.93 10.96,4.93 13.585,7.209C13.793,7.39 14.109,7.392 14.304,7.197L15.011,6.49Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M5.465,8.964C5.27,8.769 5.269,8.45 5.481,8.273C7.515,6.576 10.487,6.576 12.521,8.273C12.733,8.45 12.732,8.769 12.537,8.964L11.83,9.672C11.634,9.867 11.319,9.863 11.099,9.698C9.859,8.767 8.143,8.767 6.904,9.698C6.683,9.863 6.368,9.867 6.173,9.672L5.465,8.964Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M10.062,11.439C10.257,11.244 10.259,10.92 10.022,10.779C9.395,10.407 8.608,10.407 7.98,10.779C7.743,10.92 7.745,11.244 7.94,11.439L8.647,12.146C8.843,12.342 9.159,12.342 9.355,12.146L10.062,11.439Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_3_error.xml b/packages/SettingsLib/res/drawable/ic_wifi_3_error.xml
new file mode 100644
index 0000000..940781b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_wifi_3_error.xml
@@ -0,0 +1,25 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="17dp"
+        android:height="13dp"
+        android:viewportWidth="17.0"
+        android:viewportHeight="13.0">
+    <path
+        android:pathData="M0.146,4.015C-0.05,3.819 -0.05,3.502 0.153,3.314C4.002,-0.244 9.545,-0.937 14.055,1.234C13.339,1.449 12.792,2.053 12.66,2.801C8.998,1.281 4.65,1.924 1.568,4.73C1.364,4.916 1.048,4.917 0.853,4.722L0.146,4.015Z"
+        android:fillAlpha="0.3"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M12.63,4.435C9.406,2.836 5.424,3.288 2.63,5.792C2.424,5.976 2.425,6.294 2.621,6.49L3.328,7.197C3.523,7.392 3.839,7.39 4.047,7.209C6.484,5.094 10.033,4.942 12.63,6.753V4.435Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M5.095,8.964C4.9,8.769 4.899,8.45 5.111,8.273C7.145,6.576 10.117,6.576 12.151,8.273C12.363,8.45 12.362,8.769 12.166,8.964L11.459,9.672C11.264,9.867 10.949,9.863 10.728,9.698C9.489,8.767 7.773,8.767 6.533,9.698C6.313,9.863 5.998,9.867 5.802,9.672L5.095,8.964Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M9.652,10.779C9.889,10.92 9.887,11.244 9.692,11.439L8.984,12.146C8.789,12.342 8.473,12.342 8.277,12.146L7.57,11.439C7.375,11.244 7.373,10.92 7.61,10.779C8.237,10.407 9.024,10.407 9.652,10.779Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.63,11.15C14.63,10.598 15.078,10.15 15.63,10.15C16.182,10.15 16.63,10.598 16.63,11.15C16.63,11.703 16.182,12.15 15.63,12.15C15.078,12.15 14.63,11.703 14.63,11.15Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.63,3.15C14.63,2.874 14.854,2.65 15.13,2.65H16.13C16.406,2.65 16.63,2.874 16.63,3.15V8.15C16.63,8.427 16.406,8.65 16.13,8.65H15.13C14.854,8.65 14.63,8.427 14.63,8.15V3.15Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_4.xml b/packages/SettingsLib/res/drawable/ic_wifi_4.xml
new file mode 100644
index 0000000..6185e4a
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_wifi_4.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="18dp"
+        android:height="13dp"
+        android:viewportWidth="18.0"
+        android:viewportHeight="13.0">
+    <path
+        android:pathData="M0.523,3.314C0.32,3.502 0.32,3.819 0.516,4.015L1.223,4.722C1.418,4.917 1.734,4.916 1.938,4.73C5.936,1.09 12.066,1.09 16.064,4.73C16.268,4.916 16.584,4.917 16.779,4.722L17.486,4.015C17.682,3.819 17.682,3.502 17.479,3.314C12.698,-1.105 5.304,-1.105 0.523,3.314Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M15.011,6.49C15.207,6.294 15.207,5.976 15.002,5.792C11.592,2.736 6.411,2.736 3,5.792C2.795,5.976 2.795,6.294 2.991,6.49L3.698,7.197C3.893,7.392 4.209,7.39 4.417,7.209C7.042,4.93 10.96,4.93 13.585,7.209C13.793,7.39 14.109,7.392 14.304,7.197L15.011,6.49Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M5.465,8.964C5.27,8.769 5.269,8.45 5.481,8.273C7.515,6.576 10.487,6.576 12.521,8.273C12.733,8.45 12.732,8.769 12.537,8.964L11.83,9.672C11.634,9.867 11.319,9.863 11.099,9.698C9.859,8.767 8.143,8.767 6.904,9.698C6.683,9.863 6.368,9.867 6.173,9.672L5.465,8.964Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M10.062,11.439C10.257,11.244 10.259,10.92 10.022,10.779C9.395,10.407 8.608,10.407 7.98,10.779C7.743,10.92 7.745,11.244 7.94,11.439L8.647,12.146C8.843,12.342 9.159,12.342 9.355,12.146L10.062,11.439Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_wifi_4_error.xml b/packages/SettingsLib/res/drawable/ic_wifi_4_error.xml
new file mode 100644
index 0000000..715aaa0
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_wifi_4_error.xml
@@ -0,0 +1,24 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="17dp"
+        android:height="13dp"
+        android:viewportWidth="17.0"
+        android:viewportHeight="13.0">
+    <path
+        android:pathData="M0.146,4.015C-0.05,3.819 -0.05,3.502 0.153,3.314C4.002,-0.244 9.545,-0.937 14.055,1.234C13.339,1.449 12.792,2.053 12.66,2.801C8.998,1.281 4.65,1.924 1.568,4.73C1.364,4.916 1.048,4.917 0.853,4.722L0.146,4.015Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M12.63,4.435C9.406,2.836 5.424,3.288 2.63,5.792C2.424,5.976 2.425,6.294 2.621,6.49L3.328,7.197C3.523,7.392 3.839,7.39 4.047,7.209C6.484,5.094 10.033,4.942 12.63,6.753V4.435Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M5.095,8.964C4.9,8.769 4.899,8.45 5.111,8.273C7.145,6.576 10.117,6.576 12.151,8.273C12.363,8.45 12.362,8.769 12.166,8.964L11.459,9.672C11.264,9.867 10.949,9.863 10.728,9.698C9.489,8.767 7.773,8.767 6.533,9.698C6.313,9.863 5.998,9.867 5.802,9.672L5.095,8.964Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M9.652,10.779C9.889,10.92 9.887,11.244 9.692,11.439L8.984,12.146C8.789,12.342 8.473,12.342 8.277,12.146L7.57,11.439C7.375,11.244 7.373,10.92 7.61,10.779C8.237,10.407 9.024,10.407 9.652,10.779Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.63,11.15C14.63,10.598 15.078,10.15 15.63,10.15C16.182,10.15 16.63,10.598 16.63,11.15C16.63,11.703 16.182,12.15 15.63,12.15C15.078,12.15 14.63,11.703 14.63,11.15Z"
+        android:fillColor="#000"/>
+    <path
+        android:pathData="M14.63,3.15C14.63,2.874 14.854,2.65 15.13,2.65H16.13C16.406,2.65 16.63,2.874 16.63,3.15V8.15C16.63,8.427 16.406,8.65 16.13,8.65H15.13C14.854,8.65 14.63,8.427 14.63,8.15V3.15Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 8d3582a..cc23f6e 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Geneutraliseer deur <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Laaiproses is onderbreek om battery te beskerm"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Kontroleer tans laaibykomstigheid"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Gaan die laaibykomstigheid na"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> oor"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> oor (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> oor gegrond op jou gebruik"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> oor tot vol"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> oor tot vol"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – Laaiproses word geoptimeer"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – Laai tans"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Onbekend"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Laai"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Laai tans vinnig"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index f6931ad..0ecd376 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"በ<xliff:g id="TITLE">%1$s</xliff:g> ተሽሯል"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ባትሪን ለመጠበቅ ኃይል መሙላት በይቆይ ላይ"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - የኃይል መሙያ መለዋወጫዎችን በመፈተሽ ላይ"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - የኃይል መሙላት መለዋወጫን ይፈትሹ"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ገደማ ቀርቷል"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>) ገደማ ቀርቷል"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"በአጠቃቀምዎ መሠረት <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ገደማ ቀርቷል"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"እስኪሞላ ድረስ <xliff:g id="TIME">%1$s</xliff:g> ይቀራል"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - እስኪሞላ ድረስ <xliff:g id="TIME">%2$s</xliff:g> ይቀራል"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - ኃይል መሙላት እንዲተባ ተደርጓል"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - ኃይል በመሙላት ላይ"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ያልታወቀ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ኃይል በመሙላት ላይ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ኃይል በፍጥነት በመሙላት ላይ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 92dc69c..1f313ae 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"تم الاستبدال بـ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"‫<xliff:g id="LEVEL">%1$s</xliff:g> - الشحن معلَّق لحماية البطارية"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"‫<xliff:g id="LEVEL">%1$s</xliff:g> - يجب فحص ملحق الشحن"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - فحص ملحق الشحن"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"يتبقى <xliff:g id="TIME_REMAINING">%1$s</xliff:g> تقريبًا."</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"يتبقى <xliff:g id="TIME_REMAINING">%1$s</xliff:g> تقريبًا (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"يتبقى <xliff:g id="TIME_REMAINING">%1$s</xliff:g> تقريبًا، بناءً على استخدامك"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"يتبقّى <xliff:g id="TIME">%1$s</xliff:g> حتى اكتمال شحن البطارية."</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - يتبقّى <xliff:g id="TIME">%2$s</xliff:g> حتى اكتمال شحن البطارية."</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - تم تحسين الشحن"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"‫<xliff:g id="LEVEL">%1$s</xliff:g>: جارٍ الشحن"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"غير معروف"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"جارٍ الشحن"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"جارٍ الشحن سريعًا"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 48d3df4..a4be8e9 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g>ৰ দ্বাৰা অগ্ৰাহ্য কৰা হৈছে"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - বেটাৰী সুৰক্ষিত কৰিবলৈ চাৰ্জিং স্থগিত ৰখা হৈছে"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - চাৰ্জিঙৰ আনুষংগিক বস্তু পৰীক্ষা কৰি থকা হৈছে"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - চাৰ্জিঙৰ সৈতে জড়িত আনুষংগিক সামগ্ৰী পৰীক্ষা কৰক"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"প্রায় <xliff:g id="TIME_REMAINING">%1$s</xliff:g> বাকী আছে"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"প্রায় <xliff:g id="TIME_REMAINING">%1$s</xliff:g> বাকী আছে (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"আপোনাৰ ব্যৱহাৰৰ ওপৰত ভিত্তি কৰি প্ৰায় <xliff:g id="TIME_REMAINING">%1$s</xliff:g> বাকী আছে"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"সম্পূৰ্ণ হ’বলৈ <xliff:g id="TIME">%1$s</xliff:g> বাকী আছে"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"সম্পূৰ্ণ হ’বলৈ <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> বাকী আছে"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - চাৰ্জিং অপ্টিমাইজ কৰা হৈছে"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ চাৰ্জ হৈ আছে"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"অজ্ঞাত"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"চাৰ্জ কৰি থকা হৈছে"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"দ্ৰুততাৰে চাৰ্জ হৈছে"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index e27a40c..df6dad2 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> tərəfindən qəbul edilmir"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Batareyanı qorumaq üçün şarj gözlədilir"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj aksesuarı yoxlanır"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj aksesuarını yoxlayın"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Təxminən <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qalıb"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Təxminən <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qalıb (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"İstifadəyə əsasən təxminən <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qalıb"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Tam şarj edilənədək <xliff:g id="TIME">%1$s</xliff:g> qalıb"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - tam şarj edilənədək <xliff:g id="TIME">%2$s</xliff:g> qalıb"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj optimallaşdırılıb"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj edilir"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Naməlum"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Enerji doldurma"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Sürətlə doldurulur"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index dd48b70..8bb8c83 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Zamenjuje ga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>–<xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje je na čekanju da bi se zaštitila baterija"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – provera dodatne opreme za punjenje"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Proverite dodatnu opremu za punjenje"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Preostalo je oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Preostalo je oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Preostalo je oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g> na osnovu korišćenja"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do kraja punjenja"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do kraja punjenja"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje je optimizovano"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – Punjenje"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Puni se"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo se puni"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 48247a0..433c243 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Перавызначаны <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарадка прыпынена, каб абараніць акумулятар"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – правяраецца зарадная прылада"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g>, праверце зарадную прыладу"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Зараду хопіць прыблізна на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Зараду (<xliff:g id="LEVEL">%2$s</xliff:g>) хопіць прыблізна на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Зараду пры такім выкарыстанні хопіць прыблізна на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Да поўнай зарадкі засталося <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – да поўнай зарадкі засталося: <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – Зарадка аптымізавана"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – зараджаецца"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Невядома"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Зарадка"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Хуткая зарадка"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 035b1dd..27e27be 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Заменено от „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Зареждането е поставено на пауза с цел запазване на батерията"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Аксесоарът за зареждане се проверява"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Проверете аксесоара за зареждане"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Още около <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Още около <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Още около <xliff:g id="TIME_REMAINING">%1$s</xliff:g> въз основа на използването"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Оставащо време до пълно зареждане: <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – Оставащо време до пълно зареждане: <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – Зареждането е оптимизирано"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарежда се"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Неизвестно"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Зарежда се"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Зарежда се бързо"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 9a2f88c..2cf0556 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> এর দ্বারা ওভাররাইড করা হয়েছে"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ব্যাটারিকে সুরক্ষিত রাখতে চার্জিং হোল্ড করা হয়েছে"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - চার্জিংয়ের সরঞ্জাম চেক করা হচ্ছে"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - চার্জিং অ্যাক্সেসরি চেক করুন"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"আর আনুমানিক <xliff:g id="TIME_REMAINING">%1$s</xliff:g> চলবে"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"আর আনুমানিক <xliff:g id="TIME_REMAINING">%1$s</xliff:g> চলবে (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"ব্যবহারের উপর ভিত্তি করে আর আনুমানিক <xliff:g id="TIME_REMAINING">%1$s</xliff:g> চলবে"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g>-এ ব্যাটারি পুরো চার্জ হয়ে যাবে"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>-এ ব্যাটারি পুরো চার্জ হয়ে যাবে"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - চার্জিং অপ্টিমাইজ করা হয়েছে"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - চার্জ করা হচ্ছে"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"অজানা"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"চার্জ হচ্ছে"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"দ্রুত চার্জ হচ্ছে"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 01662dd..64ccf98 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Zamjenjuje <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje je na čekanju radi zaštite baterije"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – provjera opreme za punjenje"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – provjerite opremu za punjenje"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Preostalo je još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Preostalo je još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Preostalo je još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g> na osnovu vaše potrošnje"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do potpune napunjenosti"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do potpune napunjenosti"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje je optimizirano"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Punjenje"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo punjenje"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 61898881..81f9e97a 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"S\'ha substituït per <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>: <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g>: la càrrega s\'ha posat en espera per protegir la bateria"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g>: s\'està comprovant l\'accessori de càrrega"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g>: revisa l\'accessori de càrrega"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Temps restant aproximat: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Temps restant aproximat: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Temps restant aproximat segons l\'ús que en fas: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> per completar la càrrega"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> per completar la càrrega"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g>: càrrega optimitzada"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g>: s\'està carregant"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconegut"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"S\'està carregant"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregant ràpidament"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index ec104b4..cb8c36b 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Přepsáno nastavením <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Nabíjení je pozastaveno za účelem ochrany baterie"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Kontrola nabíjecího příslušenství"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Zkontrolujte nabíjecí příslušenství"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Zbývá asi <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Zbývá asi <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Při vašem obvyklém využití zbývá asi <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do úplného nabití"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabití"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – optimalizované nabíjení"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – Nabíjení"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Neznámé"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Nabíjí se"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Rychlé nabíjení"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index b92fc04..625f05b 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Tilsidesat af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Opladningen er sat på pause for at beskytte batteriet"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Tjekker opladningstilbehøret"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Tjek opladningstilbehøret"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ca. <xliff:g id="TIME_REMAINING">%1$s</xliff:g> tilbage"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Ca. <xliff:g id="TIME_REMAINING">%1$s</xliff:g> tilbage (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Ca. <xliff:g id="TIME_REMAINING">%1$s</xliff:g> tilbage, alt efter hvordan du bruger enheden"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Fuldt opladet om <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – fuldt opladet om <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – opladning er optimeret"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – oplades"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Ukendt"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Oplader"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Oplader hurtigt"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index debdb1e..f622f61 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Außer Kraft gesetzt von \"<xliff:g id="TITLE">%1$s</xliff:g>\""</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Ladevorgang zum Schutz des Akkus angehalten"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Ladezubehör wird geprüft"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Ladezubehör prüfen"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Noch etwa <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Noch etwa <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Bei deinem Nutzungsmuster hast du noch ca. <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Voll in <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – voll in <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – Laden wird optimiert"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – Wird geladen"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Unbekannt"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Wird aufgeladen"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Schnelles Aufladen"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 6cf0559..861f472 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Αντικαταστάθηκε από <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Η φόρτιση τέθηκε σε αναμονή για προστασία της μπαταρίας"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Έλεγχος αξεσουάρ φόρτισης"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Έλεγχος αξεσουάρ φόρτισης"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Απομένει/ουν περίπου <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Απομένει/ουν περίπου <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Απομένει/ουν περίπου <xliff:g id="TIME_REMAINING">%1$s</xliff:g>, βάσει της χρήσης σας"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Απομένουν <xliff:g id="TIME">%1$s</xliff:g> για πλήρη φόρτιση"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - Απομένουν <xliff:g id="TIME">%2$s</xliff:g> για πλήρη φόρτιση"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Η φόρτιση βελτιστοποιήθηκε"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ Φόρτιση"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Άγνωστο"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Φόρτιση"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ταχεία φόρτιση"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index b2c5718..e6923de 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Charging on hold to protect battery"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Checking charging accessory"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – check charging accessory"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left based on your usage"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> left until full"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> left until full"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging optimised"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – charging"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 21fff5e..36dfd2f 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging on hold to protect battery"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Checking charging accessory"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Check charging accessory"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left based on your usage"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index b2c5718..e6923de 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Charging on hold to protect battery"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Checking charging accessory"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – check charging accessory"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left based on your usage"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> left until full"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> left until full"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging optimised"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – charging"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index b2c5718..e6923de 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Charging on hold to protect battery"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Checking charging accessory"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – check charging accessory"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left based on your usage"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> left until full"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> left until full"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging optimised"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – charging"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 25e2779..8b05e12 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‏‎‏‎‏‎‏‏‎‏‎‎‎‎‏‎‏‏‎‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‎Overridden by ‎‏‎‎‏‏‎<xliff:g id="TITLE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎‏‏‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="PERCENTAGE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ - ‎‏‎‎‏‏‎<xliff:g id="TIME_STRING">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‎‎‏‏‎‎‎‎‏‎‎‏‏‏‏‎‎‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="LEVEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎ - Charging on hold to protect battery‎‏‎‎‏‎"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‏‏‎‎‎‎‎‏‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‏‎‎‎‎‎‎‏‎‏‏‏‎‏‏‏‎‏‎‎‎‎‏‎‏‏‏‎‏‏‏‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="LEVEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎ - Checking charging accessory‎‏‎‎‏‎"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‎‎‎‏‏‎‏‏‏‏‎‎‎‏‎‏‎‏‎‏‏‎‏‎‎‏‎‏‎‎‎‎‏‎‎‎‏‏‎‏‎‏‏‎‏‏‎‎‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="LEVEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎ - Check charging accessory‎‏‎‎‏‎"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‏‏‎‎‏‎‏‏‎‏‏‏‎‏‏‎‏‎‎‏‏‏‎About ‎‏‎‎‏‏‎<xliff:g id="TIME_REMAINING">%1$s</xliff:g>‎‏‎‎‏‏‏‎ left‎‏‎‎‏‎"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‎‏‏‏‏‎‎‎‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‎‎‎‏‎‏‏‎‎‎‎‎‎‎‎‏‎‏‎‏‏‏‎‎‏‏‎‎‏‎‎‎About ‎‏‎‎‏‏‎<xliff:g id="TIME_REMAINING">%1$s</xliff:g>‎‏‎‎‏‏‏‎ left (‎‏‎‎‏‏‎<xliff:g id="LEVEL">%2$s</xliff:g>‎‏‎‎‏‏‏‎)‎‏‎‎‏‎"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‏‎‏‎‎‏‎‏‏‎‎‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‏‎‏‏‎‏‎‎‎‏‏‎‎‎‏‎‎‎‎‏‎‎‎‎‎‏‎‎About ‎‏‎‎‏‏‎<xliff:g id="TIME_REMAINING">%1$s</xliff:g>‎‏‎‎‏‏‏‎ left based on your usage‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index d0ba34c..a6fdf56 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Reemplazado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Se detuvo la carga para proteger la batería"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Verificando el accesorio de carga"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Verifica el accesorio de carga"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tiempo restante: aproximadamente <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Tiempo restante: aproximadamente <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Tiempo restante: aproximadamente <xliff:g id="TIME_REMAINING">%1$s</xliff:g> en función de tu uso"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> para completar"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carga optimizada"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - Cargando"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconocido"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rápidamente"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 77049e0..d57a33a 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>: <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carga pausada para proteger la batería"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Comprobando accesorio de carga"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Comprueba el accesorio de carga"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tiempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Tiempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Tiempo restante aproximado según tu uso: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> hasta la carga completa"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> hasta la carga completa"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carga optimizada"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ Cargar"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconocido"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carga rápida"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 6a3c208..dfe78d8 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Alistas <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – laadimine on aku kaitsmiseks ootele pandud"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – laadimistarviku kontrollimine"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – kontrollige laadimistarvikut"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ligikaudu <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäänud"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Ligikaudu <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäänud (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Teie kasutuse põhjal on jäänud ligikaudu <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Täislaadimiseks kulub <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – täislaadimiseks kulub <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – laadimine on optimeeritud"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – laadimine"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Tundmatu"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Laadimine"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Kiirlaadimine"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 64e372a..3c6309d 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> hobespena gainjarri zaio"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g>: kargatze-prozesua zain dago bateria babesteko"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g>: kargatzeko osagarria egiaztatzen"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Eman begiratu bat kargatzeko osagarriari"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> inguru gelditzen dira"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> inguru gelditzen dira (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Erabilera kontuan izanda, <xliff:g id="TIME_REMAINING">%1$s</xliff:g> inguru gelditzen dira"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> guztiz kargatu arte"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Kargatzeko modu optimizatua"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ Kargatzen"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Ezezaguna"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Kargatzen"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Bizkor kargatzen"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 01d4618..2cb1873 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"توسط <xliff:g id="TITLE">%1$s</xliff:g> لغو شد"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - برای محافظت از باتری، شارژ موقتاً متوقف شده است"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - بررسی لوازم شارژ"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - لوازم شارژ را بررسی کنید"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"تقریباً <xliff:g id="TIME_REMAINING">%1$s</xliff:g> شارژ باقی مانده است"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"تقریباً <xliff:g id="TIME_REMAINING">%1$s</xliff:g> شارژ باقی مانده است (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"براساس مصرفتان، تقریباً <xliff:g id="TIME_REMAINING">%1$s</xliff:g> شارژ باقی مانده است"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> تا شارژ کامل باقی مانده است"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> تا شارژ کامل باقی مانده است"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - شارژ بهینه شده است"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - درحال شارژ"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ناشناس"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"در حال شارژ شدن"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"درحال شارژ شدن سریع"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 529bed5..29459ca 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Tämän ohittaa <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Lataus on keskeytetty akun suojaamiseksi"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Tarkistetaan latauslisävarustetta"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Tarkista latauslisävaruste"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Noin <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäljellä"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Noin <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäljellä (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Noin <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäljellä käyttösi perusteella"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> kunnes täynnä"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> kunnes täynnä"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – Lataus optimoitu"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – Ladataan"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Tuntematon"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Ladataan"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Nopea lataus"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index ea23834..f97b36e 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -257,7 +257,7 @@
     <string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Association de l\'appareil en cours…"</string>
     <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Échec de l\'association de l\'appareil Soit le code QR est incorrect, soit l\'appareil n\'est pas connecté au même réseau."</string>
     <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Adresse IP et port"</string>
-    <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Numériser le code QR"</string>
+    <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Balayer le code QR"</string>
     <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Associer l\'appareil par Wi-Fi en numérisant un code QR"</string>
     <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Veuillez vous connecter à un réseau Wi-Fi"</string>
     <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, débogage, développeur"</string>
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> : <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – La recharge a été mise en pause pour protéger la pile"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Vérification de l\'accessoire de recharge en cours…"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Vérifier l\'accessoire de recharge"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Il reste environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Il reste environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Il reste environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> en fonction de votre usage"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> jusqu\'à la recharge complète"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> (<xliff:g id="TIME">%2$s</xliff:g> jusqu\'à la recharge complète)"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Recharge optimisée"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – Recharge en cours…"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Inconnu"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Charge en cours…"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Recharge rapide"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index dbf107a..7f7ba63 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Recharge en pause pour protéger la batterie"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Vérification de l\'accessoire de recharge"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> : vérifiez l\'accessoire de recharge"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Temps restant : environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Temps restant : environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Temps restant en fonction de votre utilisation : environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Chargée à 100 %% dans <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - chargée à 100 %% dans <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Recharge optimisée"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - En charge"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Inconnu"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Batterie en charge"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charge rapide"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 233c9d4..179d946 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g>. A carga púxose en pausa para protexer a batería"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g>. Comprobando accesorio de carga"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g>. Comproba o accesorio de carga"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Tempo restante aproximado (<xliff:g id="LEVEL">%2$s</xliff:g>): <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Tempo restante aproximado en función do uso: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> para completar a carga"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> (<xliff:g id="TIME">%2$s</xliff:g> para completar a carga)"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> (carga optimizada)"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> (cargando)"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Descoñecido"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rapidamente"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 762ed28..cafe86c 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> દ્વારા ઓવરરાઇડ થયું"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - બૅટરીને સુરક્ષિત રાખવા માટે, ચાર્જિંગ હોલ્ડ પર રાખવામાં આવ્યું છે"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ચાર્જિંગ ઍક્સેસરી ચેક કરી રહ્યાં છીએ"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - ચાર્જિંગ ઍક્સેસરી ચેક કરો"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"લગભગ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> બાકી છે"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"લગભગ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> બાકી છે (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"તમારા વપરાશના આધારે લગભગ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> બાકી છે"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"પૂર્ણ ચાર્જ થવામાં <xliff:g id="TIME">%1$s</xliff:g> બાકી છે"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - પૂર્ણ ચાર્જ થવામાં <xliff:g id="TIME">%2$s</xliff:g> બાકી છે"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - ચાર્જિંગ ઑપ્ટિમાઇઝ કરવામાં આવ્યું છે"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - ચાર્જિંગ"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"અજાણ્યું"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ચાર્જ થઈ રહ્યું છે"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ઝડપથી ચાર્જ થાય છે"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 6a0e3e0..53cf724 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> के द्वारा ओवरराइड किया गया"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - बैटरी को सुरक्षित रखने के लिए, फ़ोन को चार्ज होने से रोक दिया गया है"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिंग ऐक्सेसरी की जांच की जा रही है"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिंग ऐक्सेसरी की जांच करें"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"आपके इस्तेमाल के हिसाब से बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> में बैटरी पूरी चार्ज हो जाएगी"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> में बैटरी पूरी चार्ज हो जाएगी"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिंग को ऑप्टिमाइज़ किया गया"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्ज हो रही है"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हो रही है"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"तेज़ चार्ज हो रही है"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index f019936..f06baad 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Premošćeno postavkom <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje je pauzirano radi zaštite baterije"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – provjera dodatka za punjenje"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – provjerite dodatak za punjenje"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Još otprilike <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Još otprilike <xliff:g id="TIME_REMAINING">%1$s</xliff:g> na temelju vaše upotrebe"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do napunjenosti"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do napunjenosti"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje se optimizira"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Punjenje"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo punjenje"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index d3d2960..39d905f 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Felülírva erre: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Az akkumulátor védelme érdekében a töltés szünetel"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Akkumulátortartozék ellenőrzése…"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Ellenőrizze a töltőtartozékot"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Körülbelül <xliff:g id="TIME_REMAINING">%1$s</xliff:g> maradt hátra"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Körülbelül <xliff:g id="TIME_REMAINING">%1$s</xliff:g> maradt hátra (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Körülbelül <xliff:g id="TIME_REMAINING">%1$s</xliff:g> maradt hátra az eszköz használata alapján"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> a teljes töltöttségig"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> a teljes töltöttségig"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – Optimalizált töltés"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – Töltés…"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Ismeretlen"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Töltés"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Gyorstöltés"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 4c14ae1..55f09e2 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Գերազանցված է <xliff:g id="TITLE">%1$s</xliff:g>-ից"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Լիցքավորումը դադարեցվել է՝ մարտկոցը պաշտպանելու համար"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Լիցքավորման սարքը ստուգվում է"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Ստուգեք լիցքավորիչը"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Լիցքը կբավարարի մոտ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Լիցքը (<xliff:g id="LEVEL">%2$s</xliff:g>) կբավարարի մոտ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Լիցքը կբավարարի մոտ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>՝ կախված օգտագործման եղանակից"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> մինչև լրիվ լիցքավորումը"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> մինչև լրիվ լիցքավորումը"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – Լիցքավորումն օպտիմալացված է"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> — Լիցքավորում"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Անհայտ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Լիցքավորում"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Արագ լիցքավորում"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 1379ecf..885729d 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Digantikan oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengisian daya dihentikan sementara untuk melindungi baterai"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Memeriksa aksesori pengisi daya"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Periksa aksesori pengisian daya"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Sekitar <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Sekitar <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Sekitar <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi berdasarkan penggunaan Anda"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> lagi sampai penuh"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> lagi sampai penuh"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengisian daya dioptimalkan"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - Mengisi daya"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Tidak diketahui"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Mengisi daya"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mengisi daya cepat"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index e48d063..020191b 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Hnekkt af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Hleðsla í bið til að vernda rafhlöðuna"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Athugar hleðslutæki"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Athugaðu hleðslubúnaðinn"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Um það bil <xliff:g id="TIME_REMAINING">%1$s</xliff:g> eftir"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Um það bil <xliff:g id="TIME_REMAINING">%1$s</xliff:g> eftir (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Um það bil <xliff:g id="TIME_REMAINING">%1$s</xliff:g> eftir miðað við notkun þína"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> fram að fullri hleðslu"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> fram að fullri hleðslu"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – Hleðsla fínstillt"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ Í hleðslu"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Óþekkt"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Í hleðslu"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hröð hleðsla"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index b335514..37a2067 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Valore sostituito da <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ricarica in sospeso per proteggere la batteria"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Controllo dell\'accessorio di ricarica"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Controlla l\'accessorio di ricarica"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo rimanente: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> circa"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Tempo rimanente: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> circa (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Tempo rimanente in base al tuo utilizzo: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> circa"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> alla ricarica completa"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> alla ricarica completa"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ricarica ottimizzata"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ In carica"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Sconosciuta"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"In carica"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ricarica veloce"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index a559cc6..e3c1f65b 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -457,7 +457,8 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"נעקף על ידי <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – הטעינה הושהתה כדי להגן על הסוללה"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – מתבצעת בדיקה של אביזר הטעינה"</string>
+    <!-- no translation found for power_incompatible_charging_settings_home_page (1322050766135126880) -->
+    <skip />
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"הזמן הנותר: בערך <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"הזמן הנותר: בערך <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"הזמן הנותר על סמך השימוש שלך: בערך <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +479,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"הזמן הנותר לטעינה מלאה: <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – הזמן הנותר לטעינה מלאה: <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – הטעינה עברה אופטימיזציה"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"‫<xliff:g id="LEVEL">%1$s</xliff:g> – בטעינה"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"לא ידוע"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"בטעינה"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"הסוללה נטענת מהר"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index a7be818..d87d0f8 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g>によって上書き済み"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - バッテリーを保護するため、充電を一時停止しています"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電用アクセサリを確認しています"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電用アクセサリを確認してください"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"残り時間: 約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"残り時間: 約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>(<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"残り時間: 約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>(使用状況に基づく)"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"完了まであと <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - 完了まであと <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電が最適化されています"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電中"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"不明"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"急速充電中"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index eb06df3..7812f0b 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"უკუგებულია <xliff:g id="TITLE">%1$s</xliff:g>-ის მიერ"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – დატენვა შეჩერებულია ბატარეის დასაცავად"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – მიმდინარეობს დამტენი აქსესუარის შემოწმება"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g>: მიმდინარეობს დამტენი აქსესუარის შემოწმება"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"დარჩა დაახლოებით <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"დარჩა დაახლოებით <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"დარჩა დაახლოებით <xliff:g id="TIME_REMAINING">%1$s</xliff:g>, ბატარეის მოხმარების გათვალისწინებით"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"სრულ დატენვამდე დარჩენილია <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> — სრულ დატენვამდე დარჩენილია <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - დატენვა ოპტიმიზირებულია"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – იტენება"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"უცნობი"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"იტენება"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"სწრაფად იტენება"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 86da0a4..300d4e5 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> үстінен басқан"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g>: батареяны қорғау үшін зарядтау кідіртіледі."</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g>: зарядтау құрылғысы тексеріледі."</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарядтау құрылғысын тексеріңіз"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Шамамен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> қалды"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Шамамен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> қалды (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Пайдалану деректеріңізге сәйкес енді шамамен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> қалды"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Толық зарядталғанға дейін <xliff:g id="TIME">%1$s</xliff:g> қалды."</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: толық зарядталуға <xliff:g id="TIME">%2$s</xliff:g> қалды"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарядтау оңтайландырылды"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – Зарядталып жатыр"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Белгісіз"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Зарядталуда"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Жылдам зарядтау"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 848e904..373cfc6 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"បដិសេធ​ដោយ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - កំពុងផ្អាកការសាកថ្ម ដើម្បីការពារថ្ម"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - កំពុងពិនិត្យមើលគ្រឿងសាកថ្ម"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - ពិនិត្យមើលគ្រឿងសាកថ្ម"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"នៅសល់​ប្រហែល <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ទៀត"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"នៅសល់​ប្រហែល <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ទៀត (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"នៅសល់​ប្រហែល <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ទៀត ផ្អែក​លើការ​ប្រើប្រាស់​របស់អ្នក"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> ទៀតទើបពេញ"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - នៅសល់ <xliff:g id="TIME">%2$s</xliff:g> ទៀតទើបពេញ"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - បានបង្កើនប្រសិទ្ធភាពនៃការសាក"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - កំពុងសាកថ្ម"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"មិន​ស្គាល់"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"កំពុងសាក​ថ្ម"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"កំពុងសាកថ្មយ៉ាងឆាប់រហ័ស"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index d13019c..bf84cc48 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ಮೂಲಕ ಅತಿಕ್ರಮಿಸುತ್ತದೆ"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಬ್ಯಾಟರಿಯನ್ನು ರಕ್ಷಿಸಲು ಚಾರ್ಜಿಂಗ್ ಅನ್ನು ಹೋಲ್ಡ್‌ ಮಾಡಲಾಗಿದೆ"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಚಾರ್ಜಿಂಗ್ ಪರಿಕರವನ್ನು ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಚಾರ್ಜಿಂಗ್ ಆ್ಯಕ್ಸೆಸರಿಯನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ಸಮಯ ಬಾಕಿ ಉಳಿದಿದೆ"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"(<xliff:g id="LEVEL">%2$s</xliff:g>) ತಲುಪಲು <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ಸಮಯ ಬಾಕಿ ಉಳಿದಿದೆ"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"ನಿಮ್ಮ ಬಳಕೆಯ ಆಧಾರದ ಮೇಲೆ ಸುಮಾರು <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ಸಮಯ ಬಾಕಿ ಉಳಿದಿದೆ"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> - ಸಮಯದಲ್ಲಿ ಪೂರ್ತಿ ಚಾರ್ಜ್ ಆಗುತ್ತದೆ"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ಸಮಯದಲ್ಲಿ ಪೂರ್ತಿ ಚಾರ್ಜ್ ಆಗುತ್ತದೆ"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಚಾರ್ಜಿಂಗ್ ಅನ್ನು ಆಪ್ಟಿಮೈಸ್ ಮಾಡಲಾಗಿದೆ"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಚಾರ್ಜಿಂಗ್ ಆಗುತ್ತಿದೆ"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ಅಪರಿಚಿತ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ವೇಗದ ಚಾರ್ಜಿಂಗ್"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 3c8ad01..b184ef4 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> 우선 적용됨"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>, <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - 배터리 보호를 위해 충전 일시중지"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - 충전 액세서리 확인 중"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - 충전 액세서리 확인"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"남은 시간: 약 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"남은 시간 약 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>(<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"내 사용량을 기준으로 약 <xliff:g id="TIME_REMAINING">%1$s</xliff:g> 남음"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> 후 충전 완료"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> 후 충전 완료"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - 충전 최적화됨"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ 충전 중"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"알 수 없음"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"충전 중"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"고속 충전 중"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index cec61bb..e565e44 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> менен алмаштырылган"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батареяны коргоо үчүн кубаттоо тындырылды"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Кубаттоо шайманы текшерилүүдө"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Кубаттоо шайманын текшериңиз"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Болжол менен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> калды"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Болжол менен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> калды (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Колдонгонуңузга караганда болжол менен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> калды"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> кийин толук кубатталат"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> кийин толук кубатталат"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> — Кубаттоо жакшыртылды"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - Кубатталууда"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Белгисиз"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Кубатталууда"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ыкчам кубатталууда"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 4209259..6caaf95 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"ຖືກແທນໂດຍ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ຢຸດການສາກຊົ່ວຄາວເພື່ອປົກປ້ອງແບັດເຕີຣີ"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ກຳລັງກວດສອບອຸປະກອນເສີມສຳລັບການສາກ"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - ກວດສອບອຸປະກອນເສີມສຳລັບການສາກ"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"ເຫຼືອອີກປະມານ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"ເຫຼືອອີກປະມານ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"ເຫຼືອອີກປະມານ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ອ້າງອີງຈາກການນຳໃຊ້ຂອງທ່ານ"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"ຍັງເຫຼືອອີກ <xliff:g id="TIME">%1$s</xliff:g> ຈຶ່ງຈະສາກເຕັມ"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"ຍັງເຫຼືອອີກ <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ຈຶ່ງຈະສາກເຕັມ"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - ການສາກຖືກປັບໃຫ້ເໝາະສົມແລ້ວ"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - ກຳລັງສາກໄຟ"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ບໍ່ຮູ້ຈັກ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ກຳລັງສາກໄຟ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ກຳລັງສາກໄຟດ່ວນ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index cb0069d..bc66a80 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Nepaisyta naudojant nuostatą „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – įkrovimas pristabdytas, siekiant apsaugoti akumuliatorių"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – tikrinamas įkrovimo priedas"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – patikrinkite įkrovimo priedą"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Liko maždaug <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Liko maždaug <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Liko maždaug <xliff:g id="TIME_REMAINING">%1$s</xliff:g>, atsižvelgiant į naudojimą"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Liko <xliff:g id="TIME">%1$s</xliff:g>, kol bus visiškai įkrauta"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – liko <xliff:g id="TIME">%2$s</xliff:g>, kol bus visiškai įkrauta"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – įkrovimas optimizuotas"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – įkraunama"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nežinomas"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Kraunasi..."</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Greitai įkraunama"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index db566881..8aac7f1 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -457,7 +457,8 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Jaunā preference: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> — <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> — uzlāde apturēta, lai aizsargātu akumulatoru"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> — notiek uzlādes piederuma pārbaude"</string>
+    <!-- no translation found for power_incompatible_charging_settings_home_page (1322050766135126880) -->
+    <skip />
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Aptuvenais atlikušais laiks: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Aptuvenais atlikušais laiks: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Ņemot vērā lietojumu, atlikušais laiks: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +479,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> līdz pilnai uzlādei"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="TIME">%2$s</xliff:g> līdz pilnai uzlādei"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> — uzlāde optimizēta"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> — notiek uzlāde"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nezināms"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Uzlāde"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Notiek ātrā uzlāde"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 6738e20..70bcc210 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Прескокнато според <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - полнењето е паузирано за да се заштити батеријата"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - се проверува додатокот за полнење"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Проверете го додатокот за полнење"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Уште околу <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Уште околу <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Уште околу <xliff:g id="TIME_REMAINING">%1$s</xliff:g> според вашето користење"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> до полна батерија"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до полна батерија"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Полнењето е оптимизирано"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ се полни"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Непознато"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Се полни"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Брзо полнење"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index a5c38bc..9a297e5 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ഉപയോഗിച്ച് അസാധുവാക്കി"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ബാറ്ററി പരിരക്ഷിക്കാൻ ചാർജിംഗ് ഹോൾഡിലാണ്"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ചാർജിംഗ് ആക്സസറി പരിശോധിക്കുന്നു"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - ചാർജിംഗ് ആക്‌സസറി പരിശോധിക്കുക"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"ഏതാണ്ട് <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"ഏതാണ്ട് <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ശേഷിക്കുന്നു (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"നിങ്ങളുടെ ഉപയോഗത്തെ അടിസ്ഥാനമാക്കി ഏതാണ്ട് <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"പൂർണ്ണമാകാൻ <xliff:g id="TIME">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - പൂർണ്ണമാകാൻ <xliff:g id="TIME">%2$s</xliff:g> ശേഷിക്കുന്നു"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - ചാർജിംഗ് ഒപ്റ്റിമൈസ് ചെയ്തു"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ ചാർജ് ചെയ്യുന്നു"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"അജ്ഞാതം"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ചാർജ് ചെയ്യുന്നു"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"അതിവേഗ ചാർജിംഗ്"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index c03c89f..000e306 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Давхарласан <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батарейг хамгаалахын тулд цэнэглэхийг хүлээлгэсэн"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Цэнэглэх нэмэлт хэрэгслийг шалгаж байна"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Цэнэглэх нэмэлт хэрэгслийг шалгах"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ойролцоогоор <xliff:g id="TIME_REMAINING">%1$s</xliff:g> үлдсэн"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Ойролцоогоор <xliff:g id="TIME_REMAINING">%1$s</xliff:g> үлдсэн (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Таны хэрэглээнд үндэслэн ойролцоогоор <xliff:g id="TIME_REMAINING">%1$s</xliff:g> үлдсэн"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Дүүрэх хүртэл <xliff:g id="TIME">%1$s</xliff:g> үлдсэн"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - дүүрэх хүртэл <xliff:g id="TIME">%2$s</xliff:g> үлдсэн"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Цэнэглэх явцыг оновчилсон"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - Цэнэглэж байна"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Тодорхойгүй"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Цэнэглэж байна"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Хурдан цэнэглэж байна"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index bbe782d..6af0fbd 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारे अधिलिखित"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - बॅटरीचे संरक्षण करण्यासाठी चार्जिंग थांबवले आहे"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिंगसंबंधित ॲक्सेसरी तपासत आहे"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिंगसंबंधित ॲक्सेसरी तपासा"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"अंदाजे <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाकी आहे"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"अंदाजे <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाकी आहे (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"तुमच्‍या वापरावर आधारित अंदाजे <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाकी आहे"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"पूर्ण चार्ज होण्यासाठी <xliff:g id="TIME">%1$s</xliff:g> शिल्लक आहेत"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - पूर्ण चार्ज होण्यासाठी <xliff:g id="TIME">%2$s</xliff:g> शिल्लक आहे"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिंग ऑप्टिमाइझ केले"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ चार्ज होत आहे"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज होत आहे"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"वेगाने चार्ज होत आहे"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 3da4f08..621b469 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Diatasi oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengecasan ditunda untuk melindungi bateri"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Memeriksa aksesori pengecasan"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Periksa aksesori pengecasan"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Kira-kira <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Kira-kira <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Kira-kira <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi berdasarkan penggunaan anda"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> lagi sebelum penuh"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> lagi sebelum penuh"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengecasan dioptimumkan"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - Mengecas"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Tidak diketahui"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Mengecas"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mengecas dgn cepat"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index f4b6697..60161c3 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> မှ ကျော်၍ လုပ်ထားသည်။"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ဘက်ထရီကာကွယ်ရန် အားသွင်းခြင်းကို ခဏရပ်ထားသည်"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - အားသွင်းပစ္စည်း စစ်ဆေးနေသည်"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - အားသွင်းပစ္စည်း စစ်ရန်"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ခန့် ကျန်သည်"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ခန့် ကျန်သည် (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"သင်၏ အသုံးပြုမှု အပေါ် မူတည်၍ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ခန့် ကျန်သည်"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"အားပြည့်ရန် <xliff:g id="TIME">%1$s</xliff:g> လိုသည်"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - အားပြည့်ရန် <xliff:g id="TIME">%2$s</xliff:g> လိုသည်"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - အားသွင်းခြင်းကို အကောင်းဆုံးပြင်ဆင်ထားသည်"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - အားသွင်းနေသည်"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"မသိ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"အားသွင်းနေပါသည်"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"အမြန် အားသွင်းနေသည်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index fbdc9e3..256a71b 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overstyres av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Ladingen er satt på vent for å beskytte batteriet"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Sjekker ladetilbehøret"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Sjekk ladetilbehøret"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Omtrent <xliff:g id="TIME_REMAINING">%1$s</xliff:g> igjen"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Omtrent <xliff:g id="TIME_REMAINING">%1$s</xliff:g> igjen (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Omtrent <xliff:g id="TIME_REMAINING">%1$s</xliff:g> igjen basert på bruken din"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Fulladet om <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – Fulladet om <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – Ladingen er optimalisert"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – lader"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Ukjent"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Lader"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Lader raskt"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 245a31f9..fdd965a 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारा अधिरोहित"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ब्याट्री जोगाउन चार्जिङ होल्ड गरिएको छ"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिङ एक्सेसरीको जाँच गरिँदै छ"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिङ एक्सेसरी जाँच्नुहोस्"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"लगभग <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाँकी छ"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"लगभग <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाँकी छ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"तपाईंको प्रयोगको आधारमा लगभग <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाँकी छ"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"पूरा चार्ज हुन <xliff:g id="TIME">%1$s</xliff:g> लाग्ने छ"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - पूरा चार्ज हुन <xliff:g id="TIME">%2$s</xliff:g> लाग्ने छ"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्ज गर्ने प्रक्रिया अप्टिमाइज गरिएको छ"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्ज गरिँदै छ"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हुँदै छ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"द्रुत गतिमा चार्ज गरिँदै छ"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 4eafb57..72e57af 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overschreven door <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g>: opladen is in de wacht gezet om de batterij te beschermen"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g>: oplaadaccessoire checken"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Oplaadaccessoire checken"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Nog ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Nog ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Nog ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> op basis van je gebruik"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Vol over <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - vol over <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Opladen geoptimaliseerd"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ Opladen"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Onbekend"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Opladen"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Snel opladen"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 5a8bed4..723af10 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ଦ୍ୱାରା ଓଭର୍‌ରାଇଡ୍‌ କରାଯାଇଛି"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ବେଟେରୀକୁ ସୁରକ୍ଷିତ ରଖିବା ପାଇଁ ଚାର୍ଜିଂ ହୋଲ୍ଡରେ ଅଛି"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ଚାର୍ଜିଂ ଆକସେସୋରୀକୁ ଯାଞ୍ଚ କରାଯାଉଛି"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - ଚାର୍ଜିଂ ଆକସେସୋରୀକୁ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"ପାଖାପାଖି <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ବଳକା ଅଛି"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"ପାଖାପାଖି <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ପାଇଁ (<xliff:g id="LEVEL">%2$s</xliff:g>) ବଳକା ଅଛି"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"ଆପଣଙ୍କ ବ୍ୟବହାରକୁ ଆଧାର କରି ପାଖାପାଖି <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ବଳକା ଅଛି"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"ପୂର୍ଣ୍ଣ ହେବାକୁ ଆଉ <xliff:g id="TIME">%1$s</xliff:g> ବାକି ଅଛି"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - ପୂର୍ଣ୍ଣ ହେବାକୁ ଆଉ <xliff:g id="TIME">%2$s</xliff:g> ବାକି ଅଛି"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - ଚାର୍ଜିଂକୁ ଅପ୍ଟିମାଇଜ କରାଯାଇଛି"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ ଚାର୍ଜିଂ"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ଅଜ୍ଞାତ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ଚାର୍ଜ ହେଉଛି"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ଶୀଘ୍ର ଚାର୍ଜ ହେଉଛି"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index df1fea1..8a77c12 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ਦੁਆਰਾ ਓਵਰਰਾਈਡ ਕੀਤਾ"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਬੈਟਰੀ ਦੀ ਸੁਰੱਖਿਆ ਲਈ ਚਾਰਜਿੰਗ ਨੂੰ ਰੋਕਿਆ ਗਿਆ ਹੈ"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਚਾਰਜਿੰਗ ਐਕਸੈਸਰੀ ਦੀ ਜਾਂਚ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਚਾਰਜਿੰਗ ਐਕਸੈਸਰੀ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"ਲਗਭਗ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ਬਾਕੀ"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"ਲਗਭਗ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ਬਾਕੀ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"ਤੁਹਾਡੀ ਵਰਤੋਂ ਦੇ ਆਧਾਰ \'ਤੇ ਲਗਭਗ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ਬਾਕੀ"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"ਬੈਟਰੀ ਪੂਰੀ ਚਾਰਜ ਹੋਣ ਵਿੱਚ <xliff:g id="TIME">%1$s</xliff:g> ਬਾਕੀ"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਬੈਟਰੀ ਪੂਰੀ ਚਾਰਜ ਹੋਣ ਵਿੱਚ <xliff:g id="TIME">%2$s</xliff:g> ਬਾਕੀ"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਚਾਰਜਿੰਗ ਨੂੰ ਸੁਯੋਗ ਬਣਾਇਆ ਗਿਆ"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ਅਗਿਆਤ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ਤੇਜ਼ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index e9f9da8..375a35f 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Nadpisana przez <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – wstrzymano ładowanie, aby chronić baterię"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – sprawdzam akcesoria do ładowania"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – sprawdź akcesoria do ładowania"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Jeszcze około <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Jeszcze około <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Jeszcze około <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (na podstawie Twojego sposobu korzystania)"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do pełnego naładowania"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do pełnego naładowania"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – ładowanie zoptymalizowane"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – ładowanie"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nieznane"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Ładowanie"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Szybkie ładowanie"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 4ee1cbd..55b9db5 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carregamento suspenso para proteger a bateria"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Verificando o acessório de carregamento"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g>: verifique o acessório de carregamento"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Tempo restante aproximado, com base no seu uso: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> até a conclusão"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> até a conclusão"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carregamento otimizado"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> (carregando)"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconhecido"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Carregando"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregando rápido"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index eae5cc9..ca704e7 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carregamento em espera para proteger a bateria"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – A verificar o acessório de carregamento"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Verificar acessório de carregamento"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Resta(m) cerca de <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Resta(m) cerca de <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Resta(m) cerca de <xliff:g id="TIME_REMAINING">%1$s</xliff:g> com base na sua utilização"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> até à carga máxima"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> até à carga máxima"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g>: carregamento otimizado"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – A carregar"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconhecido"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"A carregar"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregamento rápido"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 4ee1cbd..55b9db5 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carregamento suspenso para proteger a bateria"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Verificando o acessório de carregamento"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g>: verifique o acessório de carregamento"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Tempo restante aproximado, com base no seu uso: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> até a conclusão"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> até a conclusão"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carregamento otimizado"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> (carregando)"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconhecido"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Carregando"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregando rápido"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 91261d4..fa89c1a 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Valoare înlocuită de <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Încărcarea s-a întrerupt pentru a proteja bateria"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Se verifică accesoriul de încărcare"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Verifică accesoriul de încărcare"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Timp aproximativ rămas: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Timp aproximativ rămas: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"În baza utilizării, timpul rămas este de aproximativ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> până la finalizare"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> până la finalizare"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – Încărcare optimizată"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – Se încarcă"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Necunoscut"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Se încarcă"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Se încarcă rapid"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 87b2a93..d853070 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Новая настройка: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"Уровень заряда – <xliff:g id="PERCENTAGE">%1$s</xliff:g>. <xliff:g id="TIME_STRING">%2$s</xliff:g>."</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g>, зарядка приостановлена для защиты батареи"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g>, проверяется зарядное устройство"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g>, проверьте зарядное устройство"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Заряда хватит примерно на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Заряда (<xliff:g id="LEVEL">%2$s</xliff:g>) хватит примерно на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Заряда хватит примерно на <xliff:g id="TIME_REMAINING">%1$s</xliff:g> при текущем уровне расхода"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> до полной зарядки"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до полной зарядки"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарядка оптимизирована"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – заряжается"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Неизвестно"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Идет зарядка"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Быстрая зарядка"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 72bd507..093f216 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> මගින් ඉක්මවන ලදී"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - බැටරිය ආරක්ෂා කිරීම සඳහා ආරෝපණය රඳවා තබා ඇත"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආරෝපණ ආයිත්තම පරීක්ෂා කිරීම"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආරෝපණ ආයිත්තම පරීක්ෂා කරන්න"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ක් පමණ ඉතිරියි"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ක් පමණ ඉතිරියි (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"ඔබේ භාවිතය මත පදනම්ව <xliff:g id="TIME_REMAINING">%1$s</xliff:g> පමණ ඉතිරිව ඇත"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"සම්පූර්ණ වීමට <xliff:g id="TIME">%1$s</xliff:g>ක් ඉතිරියි"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - සම්පූර්ණ වීමට <xliff:g id="TIME">%2$s</xliff:g>ක් ඉතිරියි"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආරෝපණය ප්‍රශස්ත කර ඇත"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආරෝපණය වේ"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"නොදනී"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ආරෝපණය වෙමින්"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ශීඝ්‍ර ආරෝපණය"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index dd8be3a..1c82933 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Prekonané predvoľbou <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – nabíjanie je pozastavené, aby sa chránila batéria"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – kontroluje sa nabíjacie príslušenstvo"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – skontrolujte nabíjacie príslušenstvo"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ešte približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Zostáva približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Zostáva približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g> – závisí to od intenzity využitia"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do úplného nabitia"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabitia"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Nabíjanie je optimalizované"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – nabíja sa"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Neznáme"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Nabíja sa"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Rýchle nabíjanie"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index eefb119..f97dd78 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Preglasila nastavitev: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Zaradi zaščite baterije je polnjenje na čakanju"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Preverjanje pripomočka za polnjenje"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Preverite pripomoček za polnjenje"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Še približno <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Še približno <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Glede na način uporabe še približno <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Še <xliff:g id="TIME">%1$s</xliff:g> do napolnjenosti"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – še <xliff:g id="TIME">%2$s</xliff:g> do napolnjenosti"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – polnjenje je optimizirano"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – polnjenje"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Neznano"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Polnjenje"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hitro polnjenje"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index e847c51..a802f11 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Mbivendosur nga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Karikimi është vendosur në pritje për të mbrojtur baterinë"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Po kontrollohet aksesori i karikimit"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Kontrollo aksesorin e karikimit"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Rreth <xliff:g id="TIME_REMAINING">%1$s</xliff:g> të mbetura"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Rreth <xliff:g id="TIME_REMAINING">%1$s</xliff:g> të mbetura (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Rreth <xliff:g id="TIME_REMAINING">%1$s</xliff:g> të mbetura bazuar në përdorimin tënd"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> derisa të mbushet"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> derisa të mbushet"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Karikimi u optimizua"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - Po karikohet"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"I panjohur"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Po karikohet"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Karikim i shpejtë"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index ed0e9a6..df22159 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Замењује га <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>–<xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – пуњење је на чекању да би се заштитила батерија"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – провера додатне опреме за пуњење"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Проверите додатну опрему за пуњење"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Преостало је око <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Преостало је око <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Преостало је око <xliff:g id="TIME_REMAINING">%1$s</xliff:g> на основу коришћења"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> до краја пуњења"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до краја пуњења"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – пуњење је оптимизовано"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – Пуњење"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Непознато"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Пуни се"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Брзо се пуни"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index b4de504..79b8399 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Har åsidosatts av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Laddningen har pausats för att skydda batteriet"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Kontrollerar laddningstillbehöret"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Kontrollera laddningstillbehöret"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Cirka <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kvar"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Cirka <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kvar (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Cirka <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kvar utifrån din användning"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> kvar tills fulladdat"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> kvar tills fulladdat"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Laddningen har optimerats"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – laddas"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Okänd"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Laddar"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Laddas snabbt"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 40725c9..c0ace580 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Imetanguliwa na <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Imesitisha kuchaji ili kulinda betri yako"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Inakagua kifaa cha kuchaji"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Kagua kifaa cha kuchaji"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Zimesalia takribani <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Zimesalia takribani <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Zimesalia takribani <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kulingana na jinsi unavyoitumia"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Zimesalia <xliff:g id="TIME">%1$s</xliff:g> ijae chaji"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> zimesalia ijae chaji"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Hali ya kuchaji imeboreshwa"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - Inachaji"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Haijulikani"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Inachaji"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Inachaji kwa kasi"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 2fe243a..ebca26d 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> மூலம் மேலெழுதப்பட்டது"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - பேட்டரியைப் பாதுகாப்பதற்காகச் சார்ஜிங் இடைநிறுத்தப்பட்டுள்ளது"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - சார்ஜிங் துணைக்கருவியைச் சரிபார்க்கிறது"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - சார்ஜிங் துணைக்கருவியைச் சரிபாருங்கள்"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"கிட்டத்தட்ட <xliff:g id="TIME_REMAINING">%1$s</xliff:g> மீதமுள்ளது"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"கிட்டத்தட்ட <xliff:g id="TIME_REMAINING">%1$s</xliff:g> மீதமுள்ளது (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"உபயோகத்தின் அடிப்படையில் கிட்டத்தட்ட <xliff:g id="TIME_REMAINING">%1$s</xliff:g> மீதமுள்ளது"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"முழுவதும் சார்ஜாக <xliff:g id="TIME">%1$s</xliff:g> ஆகும்"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - முழுவதும் சார்ஜாக <xliff:g id="TIME">%2$s</xliff:g> ஆகும்"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - சார்ஜிங் மேம்படுத்தப்பட்டது"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ சார்ஜாகிறது"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"அறியப்படாத"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"சார்ஜ் ஆகிறது"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"வேகமாக சார்ஜாகிறது"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 43f2b83..cf3c08a 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ద్వారా భర్తీ చేయబడింది"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - బ్యాటరీని రక్షించడానికి ఛార్జింగ్ హోల్డ్‌లో ఉంచబడింది"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ఛార్జ్ చేసే పరికరాన్ని చెక్ చేయండి"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - ఛార్జింగ్ యాక్సెసరీని ఎంచుకోండి"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> సమయం మిగిలి ఉంది"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"దాదాపు <xliff:g id="TIME_REMAINING">%1$s</xliff:g> సమయం మిగిలి ఉంది (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"మీ వినియోగం ఆధారంగా దాదాపు <xliff:g id="TIME_REMAINING">%1$s</xliff:g> సమయం మిగిలి ఉంది"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g>లో పూర్తిగా ఛార్జ్ అవుతుంది"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>లో పూర్తిగా ఛార్జ్ అవుతుంది"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - ఛార్జింగ్ ఆప్టిమైజ్ చేయబడింది"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - ఛార్జ్ అవుతోంది"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"తెలియదు"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ఛార్జ్ అవుతోంది"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"వేగవంతమైన ఛార్జింగ్"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 8395a51..a74265e 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"แทนที่โดย <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - หยุดการชาร์จชั่วคราวเพื่อถนอมแบตเตอรี่"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - กำลังตรวจสอบอุปกรณ์เสริมสำหรับการชาร์จ"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - ตรวจสอบอุปกรณ์เสริมสำหรับการชาร์จ"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"เหลืออีกประมาณ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"เหลืออีกประมาณ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"เหลืออีกประมาณ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ขึ้นอยู่กับการใช้งานของคุณ"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"อีก <xliff:g id="TIME">%1$s</xliff:g>จึงจะเต็ม"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - อีก <xliff:g id="TIME">%2$s</xliff:g> จึงจะเต็ม"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - ปรับการชาร์จให้เหมาะสมแล้ว"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ กำลังชาร์จ"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ไม่ทราบ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"กำลังชาร์จ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"กำลังชาร์จอย่างเร็ว"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index a337bd8..18d3d3b 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Na-override ng <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Naka-hold ang pag-charge para protektahan ang baterya"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Sinusuri ang accessory sa pag-charge"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Suriin ang accessory sa pag-charge"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Humigit-kumulang <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ang natitira"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Humigit-kumulang <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ang natitira (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Humigit-kumulang <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ang natitira batay sa iyong paggamit"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> na lang bago mapuno"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> na lang bago mapuno"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Naka-optimize ang pag-charge"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - Nagcha-charge"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Hindi Kilala"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Nagcha-charge"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mabilis na charge"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 43e18ed..c424115 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> tarafından geçersiz kılındı"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pili korumak için şarj beklemede"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj aksesuarı kontrol ediliyor"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj aksesuarını kontrol edin"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Yaklaşık <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kaldı"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Yaklaşık <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kaldı (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Kullanımınıza dayalı olarak yaklaşık <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kaldı"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Tamamen şarj olmasına <xliff:g id="TIME">%1$s</xliff:g> kaldı"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - Tamamen şarj olmasına <xliff:g id="TIME">%2$s</xliff:g> kaldı"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj işlemi optimize edildi"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ Şarj ediliyor"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Bilinmiyor"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Şarj oluyor"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hızlı şarj oluyor"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 984bb79..97592f9 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Замінено на <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – заряджання призупинено, щоб захистити акумулятор"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – перевірка зарядного пристрою"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – перевірте зарядний пристрій"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Залишилося приблизно <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Залишилося приблизно <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Згідно з даними про використання залишилося приблизно <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> до повного заряду"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до повного заряду"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – заряджання оптимізовано"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – заряджається"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Невідомо"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Заряджається"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Швидке заряджання"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index bc8a4674..9d34052 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> کے ذریعہ منسوخ کردیا گیا"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - بیٹری کی حفاظت کرنے کے لیے چارجنگ ہولڈ پر ہے"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - چارجنگ ایکسیسری کی جانچ کی جا رہی ہے"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - چارجنگ ایکسیسری چیک کریں"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"تقریباً <xliff:g id="TIME_REMAINING">%1$s</xliff:g> باقی ہے"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"تقریباً <xliff:g id="TIME_REMAINING">%1$s</xliff:g> باقی ہے (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"آپ کے استعمال کی بنیاد پر تقریباً <xliff:g id="TIME_REMAINING">%1$s</xliff:g> باقی ہے"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"مکمل چارج ہونے میں <xliff:g id="TIME">%1$s</xliff:g> باقی ہے"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"مکمل چارج ہونے میں <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> باقی ہے"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - چارجنگ کو بہتر بنایا گیا"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - چارج ہو رہی ہے"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"نامعلوم"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"چارج ہو رہا ہے"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"تیزی سے چارج ہو رہا ہے"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index a655dc0..bd38bb4 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> bilan almashtirildi"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Batareyani himoyalash uchun quvvatlash toʻxtatildi"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Quvvatlash aksessuari tekshirilmoqda"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Quvvatlash aksessuarini tekshiring"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Quvvati tugashiga taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Toʻlishiga <xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – Toʻlishiga <xliff:g id="TIME">%2$s</xliff:g> qoldi"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Quvvatlash optimallashtirildi"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - Quvvatlanmoqda"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Noma’lum"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Quvvat olmoqda"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Tezkor quvvat olmoqda"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 643f8ca..5b91df3 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Bị ghi đè bởi <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Đang tạm ngưng sạc để bảo vệ pin"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Đang kiểm tra phụ kiện sạc"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Hãy kiểm tra phụ kiện sạc"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Còn khoảng <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Còn khoảng <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Còn khoảng <xliff:g id="TIME_REMAINING">%1$s</xliff:g> dựa trên mức sử dụng của bạn"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> nữa là pin đầy"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> nữa là pin đầy"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – Quá trình sạc được tối ưu hoá"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> – Đang sạc"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Không xác định"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Đang sạc"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Đang sạc nhanh"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 3b08e1f..594922a 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已被“<xliff:g id="TITLE">%1$s</xliff:g>”覆盖"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - 为保护电池,已暂停充电"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - 正在检查充电配件"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - 请检查充电配件"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"大约还可使用<xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"大约还可使用<xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"根据您的使用情况,大约还可使用<xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"还需<xliff:g id="TIME">%1$s</xliff:g>充满"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - 还需<xliff:g id="TIME">%2$s</xliff:g>充满"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充电方式已优化"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - 正在充电"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"正在充电"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"正在快速充电"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index eba782e..b3aafae 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已由「<xliff:g id="TITLE">%1$s</xliff:g>」覆寫"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - 為保護電池,目前暫停充電"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - 正在檢查充電配件"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - 檢查充電配件"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"還有大約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"還有大約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"根據你的使用情況,還有大約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g>後充滿電"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充滿電"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - 已優化充電"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ 充電中"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"快速充電中"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 099ad03..c3be21a 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已改為<xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - 為保護電池,目前暫停充電"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - 正在檢查充電配件"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> · 請檢查充電配件"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"還能使用約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"目前電量為 <xliff:g id="LEVEL">%2$s</xliff:g>,還能使用約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"根據你的使用情形,還能使用約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g>後充飽"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充飽"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電效能已最佳化"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電中"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"不明"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"快速充電中"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 4d652f8..f6aaf81 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -457,7 +457,7 @@
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Igitshezwe ngaphezulu yi-<xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ukushaja kumisiwe ukuze kuvikelwe ibhethri"</string>
-    <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Kuhlolwa okokushaja"</string>
+    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> - Hlola insiza yokushaja"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Cishe u-<xliff:g id="TIME_REMAINING">%1$s</xliff:g> osele"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Cishe u-<xliff:g id="TIME_REMAINING">%1$s</xliff:g> osele (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Cishe u-<xliff:g id="TIME_REMAINING">%1$s</xliff:g> osele ngokususelwe ekusebenziseni wakho"</string>
@@ -478,8 +478,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> okusele kuze kugcwale"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> okusele kuze kugcwale"</string>
     <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ukushaja kuthuthukisiwe"</string>
-    <!-- no translation found for power_charging_future_paused (1809543660923642799) -->
-    <skip />
+    <string name="power_charging_future_paused" msgid="1809543660923642799">"Iku-<xliff:g id="LEVEL">%1$s</xliff:g> ‑ Iyashaja"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Akwaziwa"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Iyashaja"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ishaja ngokushesha"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 9588e50..a4bc235 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1085,7 +1085,7 @@
     <!-- [CHAR_LIMIT=NONE] Label for charging on hold on main page of settings -->
     <string name="power_charging_on_hold_settings_home_page"><xliff:g id="level">%1$s</xliff:g> - Charging on hold to protect battery</string>
     <!-- [CHAR_LIMIT=NONE] Label for incompatible charging accessory on main page of settings -->
-    <string name="power_incompatible_charging_settings_home_page"><xliff:g id="level">%1$s</xliff:g> - Checking charging accessory</string>
+    <string name="power_incompatible_charging_settings_home_page"><xliff:g id="level">%1$s</xliff:g> - Check charging accessory</string>
     <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery discharging -->
     <string name="power_remaining_duration_only">About <xliff:g id="time_remaining">%1$s</xliff:g> left</string>
     <!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 61c3ce7..c2c82b3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -1764,40 +1764,4 @@
     boolean getUnpairing() {
         return mUnpairing;
     }
-
-    ListenableFuture<Void> syncProfileForMemberDevice() {
-        return ThreadUtils.getBackgroundExecutor()
-            .submit(
-                () -> {
-                    List<Pair<LocalBluetoothProfile, Boolean>> toSync =
-                        Stream.of(
-                            mProfileManager.getA2dpProfile(),
-                            mProfileManager.getHeadsetProfile(),
-                            mProfileManager.getHearingAidProfile(),
-                            mProfileManager.getLeAudioProfile(),
-                            mProfileManager.getLeAudioBroadcastAssistantProfile())
-                        .filter(Objects::nonNull)
-                        .map(profile -> new Pair<>(profile, profile.isEnabled(mDevice)))
-                        .toList();
-
-                    for (var t : toSync) {
-                        LocalBluetoothProfile profile = t.first;
-                        boolean enabledForMain = t.second;
-
-                        for (var member : mMemberDevices) {
-                            BluetoothDevice btDevice = member.getDevice();
-
-                            if (enabledForMain != profile.isEnabled(btDevice)) {
-                                Log.d(TAG, "Syncing profile " + profile + " to "
-                                        + enabledForMain + " for member device "
-                                        + btDevice.getAnonymizedAddress() + " of main device "
-                                        + mDevice.getAnonymizedAddress());
-                                profile.setEnabled(btDevice, enabledForMain);
-                            }
-                        }
-                    }
-                    return null;
-                }
-            );
-    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 32eec7e..4e52c77 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -363,7 +363,6 @@
         if (profileId == BluetoothProfile.HEADSET
                 || profileId == BluetoothProfile.A2DP
                 || profileId == BluetoothProfile.LE_AUDIO
-                || profileId == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT
                 || profileId == BluetoothProfile.CSIP_SET_COORDINATOR) {
             return mCsipDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
                 state);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
index e67ec48..a49314a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -379,7 +379,6 @@
         if (hasChanged) {
             log("addMemberDevicesIntoMainDevice: After changed, CachedBluetoothDevice list: "
                     + mCachedDevices);
-            preferredMainDevice.syncProfileForMemberDevice();
         }
         return hasChanged;
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
index ca47efd..1069b71 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
@@ -346,11 +346,15 @@
         } else {
             long hiSyncId = asha.getHiSyncId(cachedDevice.getDevice());
             if (isValidHiSyncId(hiSyncId)) {
-                final HearingAidInfo.Builder infoBuilder = new HearingAidInfo.Builder()
+                final HearingAidInfo info = new HearingAidInfo.Builder()
                         .setAshaDeviceSide(asha.getDeviceSide(cachedDevice.getDevice()))
                         .setAshaDeviceMode(asha.getDeviceMode(cachedDevice.getDevice()))
-                        .setHiSyncId(hiSyncId);
-                return infoBuilder.build();
+                        .setHiSyncId(hiSyncId)
+                        .build();
+                if (DEBUG) {
+                    Log.d(TAG, "generateHearingAidInfo, " + cachedDevice + ", info=" + info);
+                }
+                return info;
             }
         }
 
@@ -358,15 +362,20 @@
         final LeAudioProfile leAudioProfile = profileManager.getLeAudioProfile();
         if (hapClientProfile == null || leAudioProfile == null) {
             Log.w(TAG, "HapClientProfile or LeAudioProfile is not supported on this device");
-        } else {
+        } else if (cachedDevice.getProfiles().stream().anyMatch(
+                p -> p instanceof HapClientProfile)) {
             int audioLocation = leAudioProfile.getAudioLocation(cachedDevice.getDevice());
             int hearingAidType = hapClientProfile.getHearingAidType(cachedDevice.getDevice());
             if (audioLocation != BluetoothLeAudio.AUDIO_LOCATION_INVALID
                     && hearingAidType != HapClientProfile.HearingAidType.TYPE_INVALID) {
-                final HearingAidInfo.Builder infoBuilder = new HearingAidInfo.Builder()
+                final HearingAidInfo info = new HearingAidInfo.Builder()
                         .setLeAudioLocation(audioLocation)
-                        .setHapDeviceType(hearingAidType);
-                return infoBuilder.build();
+                        .setHapDeviceType(hearingAidType)
+                        .build();
+                if (DEBUG) {
+                    Log.d(TAG, "generateHearingAidInfo, " + cachedDevice + ", info=" + info);
+                }
+                return info;
             }
         }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index 6ee403d..bd27c89 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -19,6 +19,7 @@
 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
 
 import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothCsipSetCoordinator;
@@ -35,6 +36,7 @@
 import android.bluetooth.BluetoothProfile.ServiceListener;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Build;
@@ -52,6 +54,8 @@
 
 import com.google.common.collect.ImmutableList;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -71,6 +75,18 @@
  * result callback.
  */
 public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
+    public static final String ACTION_LE_AUDIO_SHARING_STATE_CHANGE =
+            "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_STATE_CHANGE";
+    public static final String EXTRA_LE_AUDIO_SHARING_STATE = "BLUETOOTH_LE_AUDIO_SHARING_STATE";
+    public static final int BROADCAST_STATE_UNKNOWN = 0;
+    public static final int BROADCAST_STATE_ON = 1;
+    public static final int BROADCAST_STATE_OFF = 2;
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(
+            prefix = {"BROADCAST_STATE_"},
+            value = {BROADCAST_STATE_UNKNOWN, BROADCAST_STATE_ON, BROADCAST_STATE_OFF})
+    public @interface BroadcastState {}
+    private static final String SETTINGS_PKG = "com.android.settings";
     private static final String TAG = "LocalBluetoothLeBroadcast";
     private static final boolean DEBUG = BluetoothUtils.D;
 
@@ -89,7 +105,6 @@
                 Settings.Secure.getUriFor(
                         Settings.Secure.BLUETOOTH_LE_BROADCAST_IMPROVE_COMPATIBILITY),
             };
-
     private final Context mContext;
     private final CachedBluetoothDeviceManager mDeviceManager;
     private BluetoothLeBroadcast mServiceBroadcast;
@@ -200,6 +215,7 @@
                         Log.d(TAG, "onBroadcastMetadataChanged(), broadcastId = " + broadcastId);
                     }
                     setLatestBluetoothLeBroadcastMetadata(metadata);
+                    notifyBroadcastStateChange(BROADCAST_STATE_ON);
                 }
 
                 @Override
@@ -212,7 +228,7 @@
                                         + ", broadcastId = "
                                         + broadcastId);
                     }
-
+                    notifyBroadcastStateChange(BROADCAST_STATE_OFF);
                     stopLocalSourceReceivers();
                     resetCacheInfo();
                 }
@@ -1005,10 +1021,6 @@
 
     /** Update fallback active device if needed. */
     public void updateFallbackActiveDeviceIfNeeded() {
-        if (!isEnabled(null)) {
-            Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to no ongoing broadcast");
-            return;
-        }
         if (mServiceBroadcastAssistant == null) {
             Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to assistant profile is null");
             return;
@@ -1078,4 +1090,15 @@
                 "bluetooth_le_broadcast_fallback_active_group_id",
                 BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
     }
+
+    private void notifyBroadcastStateChange(@BroadcastState int state) {
+        if (!mContext.getPackageName().equals(SETTINGS_PKG)) {
+            Log.d(TAG, "Skip notifyBroadcastStateChange, not triggered by Settings.");
+            return;
+        }
+        Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_STATE_CHANGE);
+        intent.putExtra(EXTRA_LE_AUDIO_SHARING_STATE, state);
+        intent.setPackage(mContext.getPackageName());
+        mContext.sendBroadcast(intent);
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
index 9a19f93..ef0f6cb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
@@ -14,6 +14,8 @@
 
 package com.android.settingslib.graph;
 
+import static com.android.settingslib.flags.Flags.newStatusBarIcons;
+
 import android.animation.ArgbEvaluator;
 import android.annotation.IntRange;
 import android.content.Context;
@@ -67,6 +69,9 @@
 
     private static final long DOT_DELAY = 1000;
 
+    // Check the config for which icon we want to use
+    private static final int ICON_RES = SignalDrawable.getIconRes();
+
     private final Paint mForegroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private final Paint mTransparentPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private final int mDarkModeFillColor;
@@ -85,7 +90,7 @@
     private int mCurrentDot;
 
     public SignalDrawable(Context context) {
-        super(context.getDrawable(com.android.internal.R.drawable.ic_signal_cellular));
+        super(context.getDrawable(ICON_RES));
         final String attributionPathString = context.getString(
                 com.android.internal.R.string.config_signalAttributionPath);
         mAttributionPath.set(PathParser.createPathFromPathData(attributionPathString));
@@ -147,9 +152,17 @@
 
     private int unpackLevel(int packedState) {
         int numBins = (packedState & NUM_LEVEL_MASK) >> NUM_LEVEL_SHIFT;
+        int cutOutOffset = 0;
         int levelOffset = numBins == (CellSignalStrength.getNumSignalStrengthLevels() + 1) ? 10 : 0;
         int level = (packedState & LEVEL_MASK);
-        return level + levelOffset;
+
+        if (newStatusBarIcons()) {
+            if (isInState(STATE_CUT)) {
+                cutOutOffset = 20;
+            }
+        }
+
+        return level + levelOffset + cutOutOffset;
     }
 
     public void setDarkIntensity(float darkIntensity) {
@@ -214,7 +227,7 @@
             drawDotAndPadding(x - dotSpacing * 2, y, dotPadding, dotSize, 0);
             canvas.drawPath(mCutoutPath, mTransparentPaint);
             canvas.drawPath(mForegroundPath, mForegroundPaint);
-        } else if (isInState(STATE_CUT)) {
+        } else if (!newStatusBarIcons() && isInState(STATE_CUT)) {
             float cutX = (mCutoutWidthFraction * width / VIEWPORT);
             float cutY = (mCutoutHeightFraction * height / VIEWPORT);
             mCutoutPath.moveTo(width, height);
@@ -300,4 +313,12 @@
     public static int getCarrierChangeState(int numLevels) {
         return (STATE_CARRIER_CHANGE << STATE_SHIFT) | (numLevels << NUM_LEVEL_SHIFT);
     }
+
+    private static int getIconRes() {
+        if (newStatusBarIcons()) {
+            return R.drawable.ic_mobile_level_list;
+        } else {
+            return com.android.internal.R.drawable.ic_signal_cellular;
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 50e2f9c..5f026c4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -74,6 +74,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -84,6 +85,7 @@
 
     private static final String TAG = "InfoMediaManager";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    protected final List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
 
     /** Checked exception that signals the specified package is not present in the system. */
     public static class PackageNotAvailableException extends Exception {
@@ -139,7 +141,6 @@
         }
     }
 
-    @Override
     public void startScan() {
         mMediaDevices.clear();
         startScanOnRouter();
@@ -156,7 +157,6 @@
         }
     }
 
-    @Override
     public abstract void stopScan();
 
     protected abstract void startScanOnRouter();
@@ -229,6 +229,16 @@
         Api34Impl.onRouteListingPreferenceUpdated(routeListingPreference, mPreferenceItemMap);
     }
 
+    protected final MediaDevice findMediaDevice(@NonNull String id) {
+        for (MediaDevice mediaDevice : mMediaDevices) {
+            if (mediaDevice.getId().equals(id)) {
+                return mediaDevice;
+            }
+        }
+        Log.e(TAG, "findMediaDevice() can't find device with id: " + id);
+        return null;
+    }
+
     /**
      * Get current device that played media.
      * @return MediaDevice
@@ -435,7 +445,7 @@
 
     protected final synchronized void refreshDevices() {
         rebuildDeviceList();
-        dispatchDeviceListAdded();
+        dispatchDeviceListAdded(mMediaDevices);
     }
 
     // MediaRoute2Info.getType was made public on API 34, but exists since API 30.
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
index dfbf23f..d562c8a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
@@ -15,9 +15,9 @@
  */
 package com.android.settingslib.media;
 
+import android.annotation.NonNull;
 import android.app.Notification;
 import android.content.Context;
-import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -29,10 +29,7 @@
  */
 public abstract class MediaManager {
 
-    private static final String TAG = "MediaManager";
-
     protected final Collection<MediaDeviceCallback> mCallbacks = new CopyOnWriteArrayList<>();
-    protected final List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
 
     protected Context mContext;
     protected Notification mNotification;
@@ -54,29 +51,9 @@
         }
     }
 
-    /**
-     * Start scan connected MediaDevice
-     */
-    public abstract void startScan();
-
-    /**
-     * Stop scan MediaDevice
-     */
-    public abstract void stopScan();
-
-    protected MediaDevice findMediaDevice(String id) {
-        for (MediaDevice mediaDevice : mMediaDevices) {
-            if (mediaDevice.getId().equals(id)) {
-                return mediaDevice;
-            }
-        }
-        Log.e(TAG, "findMediaDevice() can't found device");
-        return null;
-    }
-
-    protected void dispatchDeviceListAdded() {
+    protected void dispatchDeviceListAdded(@NonNull List<MediaDevice> devices) {
         for (MediaDeviceCallback callback : getCallbacks()) {
-            callback.onDeviceListAdded(new ArrayList<>(mMediaDevices));
+            callback.onDeviceListAdded(new ArrayList<>(devices));
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java
index 0f08605..df03167 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java
@@ -41,6 +41,7 @@
 import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
@@ -64,6 +65,8 @@
                 refreshDevices();
             };
 
+    private final AtomicReference<MediaRouter2.ScanToken> mScanToken = new AtomicReference<>();
+
     // TODO (b/321969740): Plumb target UserHandle between UMO and RouterInfoMediaManager.
     /* package */ RouterInfoMediaManager(
             Context context,
@@ -101,12 +104,24 @@
                 mExecutor, mRouteListingPreferenceCallback);
         mRouter.registerTransferCallback(mExecutor, mTransferCallback);
         mRouter.registerControllerCallback(mExecutor, mControllerCallback);
-        mRouter.startScan();
+        if (Flags.enableScreenOffScanning()) {
+            MediaRouter2.ScanRequest request = new MediaRouter2.ScanRequest.Builder().build();
+            mScanToken.compareAndSet(null, mRouter.requestScan(request));
+        } else {
+            mRouter.startScan();
+        }
     }
 
     @Override
     public void stopScan() {
-        mRouter.stopScan();
+        if (Flags.enableScreenOffScanning()) {
+            MediaRouter2.ScanToken token = mScanToken.getAndSet(null);
+            if (token != null) {
+                mRouter.cancelScanRequest(token);
+            }
+        } else {
+            mRouter.stopScan();
+        }
         mRouter.unregisterControllerCallback(mControllerCallback);
         mRouter.unregisterTransferCallback(mTransferCallback);
         mRouter.unregisterRouteListingPreferenceUpdatedCallback(mRouteListingPreferenceCallback);
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/data/repository/SpatializerRepository.kt b/packages/SettingsLib/src/com/android/settingslib/media/data/repository/SpatializerRepository.kt
index 2a4658b..a5c63be 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/data/repository/SpatializerRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/media/data/repository/SpatializerRepository.kt
@@ -18,33 +18,71 @@
 
 import android.media.AudioDeviceAttributes
 import android.media.Spatializer
+import androidx.concurrent.futures.DirectExecutor
 import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 
 interface SpatializerRepository {
 
+    /** Returns true when head tracking is enabled and false the otherwise. */
+    val isHeadTrackingAvailable: StateFlow<Boolean>
+
     /**
      * Returns true when Spatial audio feature is supported for the [audioDeviceAttributes] and
      * false the otherwise.
      */
-    suspend fun isAvailableForDevice(audioDeviceAttributes: AudioDeviceAttributes): Boolean
+    suspend fun isSpatialAudioAvailableForDevice(
+        audioDeviceAttributes: AudioDeviceAttributes
+    ): Boolean
 
     /** Returns a list [AudioDeviceAttributes] that are compatible with spatial audio. */
-    suspend fun getCompatibleDevices(): Collection<AudioDeviceAttributes>
+    suspend fun getSpatialAudioCompatibleDevices(): Collection<AudioDeviceAttributes>
 
-    /** Adds a [audioDeviceAttributes] to [getCompatibleDevices] list. */
-    suspend fun addCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes)
+    /** Adds a [audioDeviceAttributes] to [getSpatialAudioCompatibleDevices] list. */
+    suspend fun addSpatialAudioCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes)
 
-    /** Removes a [audioDeviceAttributes] to [getCompatibleDevices] list. */
-    suspend fun removeCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes)
+    /** Removes a [audioDeviceAttributes] from [getSpatialAudioCompatibleDevices] list. */
+    suspend fun removeSpatialAudioCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes)
+
+    /** Checks if the head tracking is enabled for the [audioDeviceAttributes]. */
+    suspend fun isHeadTrackingEnabled(audioDeviceAttributes: AudioDeviceAttributes): Boolean
+
+    /** Sets head tracking [isEnabled] for the [audioDeviceAttributes]. */
+    suspend fun setHeadTrackingEnabled(
+        audioDeviceAttributes: AudioDeviceAttributes,
+        isEnabled: Boolean,
+    )
 }
 
 class SpatializerRepositoryImpl(
     private val spatializer: Spatializer,
+    coroutineScope: CoroutineScope,
     private val backgroundContext: CoroutineContext,
 ) : SpatializerRepository {
 
-    override suspend fun isAvailableForDevice(
+    override val isHeadTrackingAvailable: StateFlow<Boolean> =
+        callbackFlow {
+                val listener =
+                    Spatializer.OnHeadTrackerAvailableListener { _, available ->
+                        launch { send(available) }
+                    }
+                spatializer.addOnHeadTrackerAvailableListener(DirectExecutor.INSTANCE, listener)
+                awaitClose { spatializer.removeOnHeadTrackerAvailableListener(listener) }
+            }
+            .onStart { emit(spatializer.isHeadTrackerAvailable) }
+            .flowOn(backgroundContext)
+            .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), false)
+
+    override suspend fun isSpatialAudioAvailableForDevice(
         audioDeviceAttributes: AudioDeviceAttributes
     ): Boolean {
         return withContext(backgroundContext) {
@@ -52,18 +90,36 @@
         }
     }
 
-    override suspend fun getCompatibleDevices(): Collection<AudioDeviceAttributes> =
+    override suspend fun getSpatialAudioCompatibleDevices(): Collection<AudioDeviceAttributes> =
         withContext(backgroundContext) { spatializer.compatibleAudioDevices }
 
-    override suspend fun addCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) {
+    override suspend fun addSpatialAudioCompatibleDevice(
+        audioDeviceAttributes: AudioDeviceAttributes
+    ) {
         withContext(backgroundContext) {
             spatializer.addCompatibleAudioDevice(audioDeviceAttributes)
         }
     }
 
-    override suspend fun removeCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) {
+    override suspend fun removeSpatialAudioCompatibleDevice(
+        audioDeviceAttributes: AudioDeviceAttributes
+    ) {
         withContext(backgroundContext) {
             spatializer.removeCompatibleAudioDevice(audioDeviceAttributes)
         }
     }
+
+    override suspend fun isHeadTrackingEnabled(
+        audioDeviceAttributes: AudioDeviceAttributes
+    ): Boolean =
+        withContext(backgroundContext) { spatializer.isHeadTrackerEnabled(audioDeviceAttributes) }
+
+    override suspend fun setHeadTrackingEnabled(
+        audioDeviceAttributes: AudioDeviceAttributes,
+        isEnabled: Boolean,
+    ) {
+        withContext(backgroundContext) {
+            spatializer.setHeadTrackerEnabled(isEnabled, audioDeviceAttributes)
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/domain/interactor/SpatializerInteractor.kt b/packages/SettingsLib/src/com/android/settingslib/media/domain/interactor/SpatializerInteractor.kt
index c3cc340..0347403 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/domain/interactor/SpatializerInteractor.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/media/domain/interactor/SpatializerInteractor.kt
@@ -18,22 +18,40 @@
 
 import android.media.AudioDeviceAttributes
 import com.android.settingslib.media.data.repository.SpatializerRepository
+import kotlinx.coroutines.flow.StateFlow
 
 class SpatializerInteractor(private val repository: SpatializerRepository) {
 
-    suspend fun isAvailable(audioDeviceAttributes: AudioDeviceAttributes): Boolean =
-        repository.isAvailableForDevice(audioDeviceAttributes)
+    /** Checks if head tracking is available. */
+    val isHeadTrackingAvailable: StateFlow<Boolean>
+        get() = repository.isHeadTrackingAvailable
+
+    suspend fun isSpatialAudioAvailable(audioDeviceAttributes: AudioDeviceAttributes): Boolean =
+        repository.isSpatialAudioAvailableForDevice(audioDeviceAttributes)
 
     /** Checks if spatial audio is enabled for the [audioDeviceAttributes]. */
-    suspend fun isEnabled(audioDeviceAttributes: AudioDeviceAttributes): Boolean =
-        repository.getCompatibleDevices().contains(audioDeviceAttributes)
+    suspend fun isSpatialAudioEnabled(audioDeviceAttributes: AudioDeviceAttributes): Boolean =
+        repository.getSpatialAudioCompatibleDevices().contains(audioDeviceAttributes)
 
-    /** Enblaes or disables spatial audio for [audioDeviceAttributes]. */
-    suspend fun setEnabled(audioDeviceAttributes: AudioDeviceAttributes, isEnabled: Boolean) {
+    /** Enables or disables spatial audio for [audioDeviceAttributes]. */
+    suspend fun setSpatialAudioEnabled(
+        audioDeviceAttributes: AudioDeviceAttributes,
+        isEnabled: Boolean
+    ) {
         if (isEnabled) {
-            repository.addCompatibleDevice(audioDeviceAttributes)
+            repository.addSpatialAudioCompatibleDevice(audioDeviceAttributes)
         } else {
-            repository.removeCompatibleDevice(audioDeviceAttributes)
+            repository.removeSpatialAudioCompatibleDevice(audioDeviceAttributes)
         }
     }
+
+    /** Checks if head tracking is enabled for the [audioDeviceAttributes]. */
+    suspend fun isHeadTrackingEnabled(audioDeviceAttributes: AudioDeviceAttributes): Boolean =
+        repository.isHeadTrackingEnabled(audioDeviceAttributes)
+
+    /** Enables or disables head tracking for the [audioDeviceAttributes]. */
+    suspend fun setHeadTrackingEnabled(
+        audioDeviceAttributes: AudioDeviceAttributes,
+        isEnabled: Boolean,
+    ) = repository.setHeadTrackingEnabled(audioDeviceAttributes, isEnabled)
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
deleted file mode 100644
index b9a4647..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.wifi;
-
-import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED;
-import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.getMaxNetworkSelectionDisableReason;
-
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
-import android.icu.text.MessageFormat;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo;
-import android.os.Bundle;
-import android.os.SystemClock;
-import android.util.Log;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.settingslib.R;
-
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-
-public class WifiUtils {
-
-    private static final String TAG = "WifiUtils";
-
-    private static final int INVALID_RSSI = -127;
-
-    /**
-     * The intent action shows Wi-Fi dialog to connect Wi-Fi network.
-     * <p>
-     * Input: The calling package should put the chosen
-     * com.android.wifitrackerlib.WifiEntry#getKey() to a string extra in the request bundle into
-     * the {@link #EXTRA_CHOSEN_WIFI_ENTRY_KEY}.
-     * <p>
-     * Output: Nothing.
-     */
-    @VisibleForTesting
-    static final String ACTION_WIFI_DIALOG = "com.android.settings.WIFI_DIALOG";
-
-    /**
-     * Specify a key that indicates the WifiEntry to be configured.
-     */
-    @VisibleForTesting
-    static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key";
-
-    /**
-     * The lookup key for a boolean that indicates whether a chosen WifiEntry request to connect to.
-     * {@code true} means a chosen WifiEntry request to connect to.
-     */
-    @VisibleForTesting
-    static final String EXTRA_CONNECT_FOR_CALLER = "connect_for_caller";
-
-    /**
-     * The intent action shows network details settings to allow configuration of Wi-Fi.
-     * <p>
-     * In some cases, a matching Activity may not exist, so ensure you
-     * safeguard against this.
-     * <p>
-     * Input: The calling package should put the chosen
-     * com.android.wifitrackerlib.WifiEntry#getKey() to a string extra in the request bundle into
-     * the {@link #KEY_CHOSEN_WIFIENTRY_KEY}.
-     * <p>
-     * Output: Nothing.
-     */
-    public static final String ACTION_WIFI_DETAILS_SETTINGS =
-            "android.settings.WIFI_DETAILS_SETTINGS";
-    public static final String KEY_CHOSEN_WIFIENTRY_KEY = "key_chosen_wifientry_key";
-    public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args";
-
-    static final int[] WIFI_PIE = {
-            com.android.internal.R.drawable.ic_wifi_signal_0,
-            com.android.internal.R.drawable.ic_wifi_signal_1,
-            com.android.internal.R.drawable.ic_wifi_signal_2,
-            com.android.internal.R.drawable.ic_wifi_signal_3,
-            com.android.internal.R.drawable.ic_wifi_signal_4
-    };
-
-    static final int[] NO_INTERNET_WIFI_PIE = {
-            R.drawable.ic_no_internet_wifi_signal_0,
-            R.drawable.ic_no_internet_wifi_signal_1,
-            R.drawable.ic_no_internet_wifi_signal_2,
-            R.drawable.ic_no_internet_wifi_signal_3,
-            R.drawable.ic_no_internet_wifi_signal_4
-    };
-
-    public static String buildLoggingSummary(AccessPoint accessPoint, WifiConfiguration config) {
-        final StringBuilder summary = new StringBuilder();
-        final WifiInfo info = accessPoint.getInfo();
-        // Add RSSI/band information for this config, what was seen up to 6 seconds ago
-        // verbose WiFi Logging is only turned on thru developers settings
-        if (accessPoint.isActive() && info != null) {
-            summary.append(" f=" + Integer.toString(info.getFrequency()));
-        }
-        summary.append(" " + getVisibilityStatus(accessPoint));
-        if (config != null
-                && (config.getNetworkSelectionStatus().getNetworkSelectionStatus()
-                        != NETWORK_SELECTION_ENABLED)) {
-            summary.append(" (" + config.getNetworkSelectionStatus().getNetworkStatusString());
-            if (config.getNetworkSelectionStatus().getDisableTime() > 0) {
-                long now = System.currentTimeMillis();
-                long diff = (now - config.getNetworkSelectionStatus().getDisableTime()) / 1000;
-                long sec = diff % 60; //seconds
-                long min = (diff / 60) % 60; //minutes
-                long hour = (min / 60) % 60; //hours
-                summary.append(", ");
-                if (hour > 0) summary.append(Long.toString(hour) + "h ");
-                summary.append(Long.toString(min) + "m ");
-                summary.append(Long.toString(sec) + "s ");
-            }
-            summary.append(")");
-        }
-
-        if (config != null) {
-            NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus();
-            for (int reason = 0; reason <= getMaxNetworkSelectionDisableReason(); reason++) {
-                if (networkStatus.getDisableReasonCounter(reason) != 0) {
-                    summary.append(" ")
-                            .append(NetworkSelectionStatus
-                                    .getNetworkSelectionDisableReasonString(reason))
-                            .append("=")
-                            .append(networkStatus.getDisableReasonCounter(reason));
-                }
-            }
-        }
-
-        return summary.toString();
-    }
-
-    /**
-     * Returns the visibility status of the WifiConfiguration.
-     *
-     * @return autojoin debugging information
-     * TODO: use a string formatter
-     * ["rssi 5Ghz", "num results on 5GHz" / "rssi 5Ghz", "num results on 5GHz"]
-     * For instance [-40,5/-30,2]
-     */
-    @VisibleForTesting
-    static String getVisibilityStatus(AccessPoint accessPoint) {
-        final WifiInfo info = accessPoint.getInfo();
-        StringBuilder visibility = new StringBuilder();
-        StringBuilder scans24GHz = new StringBuilder();
-        StringBuilder scans5GHz = new StringBuilder();
-        StringBuilder scans60GHz = new StringBuilder();
-        String bssid = null;
-
-        if (accessPoint.isActive() && info != null) {
-            bssid = info.getBSSID();
-            if (bssid != null) {
-                visibility.append(" ").append(bssid);
-            }
-            visibility.append(" standard = ").append(info.getWifiStandard());
-            visibility.append(" rssi=").append(info.getRssi());
-            visibility.append(" ");
-            visibility.append(" score=").append(info.getScore());
-            if (accessPoint.getSpeed() != AccessPoint.Speed.NONE) {
-                visibility.append(" speed=").append(accessPoint.getSpeedLabel());
-            }
-            visibility.append(String.format(" tx=%.1f,", info.getSuccessfulTxPacketsPerSecond()));
-            visibility.append(String.format("%.1f,", info.getRetriedTxPacketsPerSecond()));
-            visibility.append(String.format("%.1f ", info.getLostTxPacketsPerSecond()));
-            visibility.append(String.format("rx=%.1f", info.getSuccessfulRxPacketsPerSecond()));
-        }
-
-        int maxRssi5 = INVALID_RSSI;
-        int maxRssi24 = INVALID_RSSI;
-        int maxRssi60 = INVALID_RSSI;
-        final int maxDisplayedScans = 4;
-        int num5 = 0; // number of scanned BSSID on 5GHz band
-        int num24 = 0; // number of scanned BSSID on 2.4Ghz band
-        int num60 = 0; // number of scanned BSSID on 60Ghz band
-        int numBlockListed = 0;
-
-        // TODO: sort list by RSSI or age
-        long nowMs = SystemClock.elapsedRealtime();
-        for (ScanResult result : accessPoint.getScanResults()) {
-            if (result == null) {
-                continue;
-            }
-            if (result.frequency >= AccessPoint.LOWER_FREQ_5GHZ
-                    && result.frequency <= AccessPoint.HIGHER_FREQ_5GHZ) {
-                // Strictly speaking: [4915, 5825]
-                num5++;
-
-                if (result.level > maxRssi5) {
-                    maxRssi5 = result.level;
-                }
-                if (num5 <= maxDisplayedScans) {
-                    scans5GHz.append(
-                            verboseScanResultSummary(accessPoint, result, bssid,
-                                    nowMs));
-                }
-            } else if (result.frequency >= AccessPoint.LOWER_FREQ_24GHZ
-                    && result.frequency <= AccessPoint.HIGHER_FREQ_24GHZ) {
-                // Strictly speaking: [2412, 2482]
-                num24++;
-
-                if (result.level > maxRssi24) {
-                    maxRssi24 = result.level;
-                }
-                if (num24 <= maxDisplayedScans) {
-                    scans24GHz.append(
-                            verboseScanResultSummary(accessPoint, result, bssid,
-                                    nowMs));
-                }
-            } else if (result.frequency >= AccessPoint.LOWER_FREQ_60GHZ
-                    && result.frequency <= AccessPoint.HIGHER_FREQ_60GHZ) {
-                // Strictly speaking: [60000, 61000]
-                num60++;
-
-                if (result.level > maxRssi60) {
-                    maxRssi60 = result.level;
-                }
-                if (num60 <= maxDisplayedScans) {
-                    scans60GHz.append(
-                            verboseScanResultSummary(accessPoint, result, bssid,
-                                    nowMs));
-                }
-            }
-        }
-        visibility.append(" [");
-        if (num24 > 0) {
-            visibility.append("(").append(num24).append(")");
-            if (num24 > maxDisplayedScans) {
-                visibility.append("max=").append(maxRssi24).append(",");
-            }
-            visibility.append(scans24GHz.toString());
-        }
-        visibility.append(";");
-        if (num5 > 0) {
-            visibility.append("(").append(num5).append(")");
-            if (num5 > maxDisplayedScans) {
-                visibility.append("max=").append(maxRssi5).append(",");
-            }
-            visibility.append(scans5GHz.toString());
-        }
-        visibility.append(";");
-        if (num60 > 0) {
-            visibility.append("(").append(num60).append(")");
-            if (num60 > maxDisplayedScans) {
-                visibility.append("max=").append(maxRssi60).append(",");
-            }
-            visibility.append(scans60GHz.toString());
-        }
-        if (numBlockListed > 0) {
-            visibility.append("!").append(numBlockListed);
-        }
-        visibility.append("]");
-
-        return visibility.toString();
-    }
-
-    @VisibleForTesting
-    /* package */ static String verboseScanResultSummary(AccessPoint accessPoint, ScanResult result,
-            String bssid, long nowMs) {
-        StringBuilder stringBuilder = new StringBuilder();
-        stringBuilder.append(" \n{").append(result.BSSID);
-        if (result.BSSID.equals(bssid)) {
-            stringBuilder.append("*");
-        }
-        stringBuilder.append("=").append(result.frequency);
-        stringBuilder.append(",").append(result.level);
-        int speed = getSpecificApSpeed(result, accessPoint.getScoredNetworkCache());
-        if (speed != AccessPoint.Speed.NONE) {
-            stringBuilder.append(",")
-                    .append(accessPoint.getSpeedLabel(speed));
-        }
-        int ageSeconds = (int) (nowMs - result.timestamp / 1000) / 1000;
-        stringBuilder.append(",").append(ageSeconds).append("s");
-        stringBuilder.append("}");
-        return stringBuilder.toString();
-    }
-
-    @AccessPoint.Speed
-    private static int getSpecificApSpeed(ScanResult result,
-            Map<String, TimestampedScoredNetwork> scoredNetworkCache) {
-        TimestampedScoredNetwork timedScore = scoredNetworkCache.get(result.BSSID);
-        if (timedScore == null) {
-            return AccessPoint.Speed.NONE;
-        }
-        // For debugging purposes we may want to use mRssi rather than result.level as the average
-        // speed wil be determined by mRssi
-        return timedScore.getScore().calculateBadge(result.level);
-    }
-
-    public static String getMeteredLabel(Context context, WifiConfiguration config) {
-        // meteredOverride is whether the user manually set the metered setting or not.
-        // meteredHint is whether the network itself is telling us that it is metered
-        if (config.meteredOverride == WifiConfiguration.METERED_OVERRIDE_METERED
-                || (config.meteredHint && !isMeteredOverridden(config))) {
-            return context.getString(R.string.wifi_metered_label);
-        }
-        return context.getString(R.string.wifi_unmetered_label);
-    }
-
-    /**
-     * Returns the Internet icon resource for a given RSSI level.
-     *
-     * @param level The number of bars to show (0-4)
-     * @param noInternet True if a connected Wi-Fi network cannot access the Internet
-     */
-    public static int getInternetIconResource(int level, boolean noInternet) {
-        int wifiLevel = level;
-        if (wifiLevel < 0) {
-            Log.e(TAG, "Wi-Fi level is out of range! level:" + level);
-            wifiLevel = 0;
-        } else if (level >= WIFI_PIE.length) {
-            Log.e(TAG, "Wi-Fi level is out of range! level:" + level);
-            wifiLevel = WIFI_PIE.length - 1;
-        }
-        return noInternet ? NO_INTERNET_WIFI_PIE[wifiLevel] : WIFI_PIE[wifiLevel];
-    }
-
-    /**
-     * Returns the Hotspot network icon resource.
-     *
-     * @param deviceType The device type of Hotspot network
-     */
-    public static int getHotspotIconResource(int deviceType) {
-        return switch (deviceType) {
-            case NetworkProviderInfo.DEVICE_TYPE_PHONE -> R.drawable.ic_hotspot_phone;
-            case NetworkProviderInfo.DEVICE_TYPE_TABLET -> R.drawable.ic_hotspot_tablet;
-            case NetworkProviderInfo.DEVICE_TYPE_LAPTOP -> R.drawable.ic_hotspot_laptop;
-            case NetworkProviderInfo.DEVICE_TYPE_WATCH -> R.drawable.ic_hotspot_watch;
-            case NetworkProviderInfo.DEVICE_TYPE_AUTO -> R.drawable.ic_hotspot_auto;
-            default -> R.drawable.ic_hotspot_phone;  // Return phone icon as default.
-        };
-    }
-
-    /**
-     * Wrapper the {@link #getInternetIconResource} for testing compatibility.
-     */
-    public static class InternetIconInjector {
-
-        protected final Context mContext;
-
-        public InternetIconInjector(Context context) {
-            mContext = context;
-        }
-
-        /**
-         * Returns the Internet icon for a given RSSI level.
-         *
-         * @param noInternet True if a connected Wi-Fi network cannot access the Internet
-         * @param level The number of bars to show (0-4)
-         */
-        public Drawable getIcon(boolean noInternet, int level) {
-            return mContext.getDrawable(WifiUtils.getInternetIconResource(level, noInternet));
-        }
-    }
-
-    public static boolean isMeteredOverridden(WifiConfiguration config) {
-        return config.meteredOverride != WifiConfiguration.METERED_OVERRIDE_NONE;
-    }
-
-    /**
-     * Returns the Intent for Wi-Fi dialog.
-     *
-     * @param key              The Wi-Fi entry key
-     * @param connectForCaller True if a chosen WifiEntry request to connect to
-     */
-    public static Intent getWifiDialogIntent(String key, boolean connectForCaller) {
-        final Intent intent = new Intent(ACTION_WIFI_DIALOG);
-        intent.putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, key);
-        intent.putExtra(EXTRA_CONNECT_FOR_CALLER, connectForCaller);
-        return intent;
-    }
-
-    /**
-     * Returns the Intent for Wi-Fi network details settings.
-     *
-     * @param key The Wi-Fi entry key
-     */
-    public static Intent getWifiDetailsSettingsIntent(String key) {
-        final Intent intent = new Intent(ACTION_WIFI_DETAILS_SETTINGS);
-        final Bundle bundle = new Bundle();
-        bundle.putString(KEY_CHOSEN_WIFIENTRY_KEY, key);
-        intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, bundle);
-        return intent;
-    }
-
-    /**
-     * Returns the string of Wi-Fi tethering summary for connected devices.
-     *
-     * @param context          The application context
-     * @param connectedDevices The count of connected devices
-     */
-    public static String getWifiTetherSummaryForConnectedDevices(Context context,
-            int connectedDevices) {
-        MessageFormat msgFormat = new MessageFormat(
-                context.getResources().getString(R.string.wifi_tether_connected_summary),
-                Locale.getDefault());
-        Map<String, Object> arguments = new HashMap<>();
-        arguments.put("count", connectedDevices);
-        return msgFormat.format(arguments);
-    }
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt
new file mode 100644
index 0000000..0117ece
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settingslib.wifi
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.graphics.drawable.Drawable
+import android.icu.text.MessageFormat
+import android.net.wifi.ScanResult
+import android.net.wifi.WifiConfiguration
+import android.net.wifi.WifiConfiguration.NetworkSelectionStatus
+import android.net.wifi.WifiManager
+import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo
+import android.os.Bundle
+import android.os.SystemClock
+import android.util.Log
+import androidx.annotation.VisibleForTesting
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import com.android.settingslib.R
+import com.android.settingslib.flags.Flags.newStatusBarIcons
+import java.util.Locale
+import kotlin.coroutines.resume
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.asExecutor
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlinx.coroutines.withContext
+
+
+open class WifiUtils {
+    /**
+     * Wrapper the [.getInternetIconResource] for testing compatibility.
+     */
+    open class InternetIconInjector(protected val context: Context) {
+        /**
+         * Returns the Internet icon for a given RSSI level.
+         *
+         * @param noInternet True if a connected Wi-Fi network cannot access the Internet
+         * @param level The number of bars to show (0-4)
+         */
+        fun getIcon(noInternet: Boolean, level: Int): Drawable? {
+            return context.getDrawable(getInternetIconResource(level, noInternet))
+        }
+    }
+
+    companion object {
+        private const val TAG = "WifiUtils"
+        private const val INVALID_RSSI = -127
+
+        /**
+         * The intent action shows Wi-Fi dialog to connect Wi-Fi network.
+         *
+         *
+         * Input: The calling package should put the chosen
+         * com.android.wifitrackerlib.WifiEntry#getKey() to a string extra in the request bundle into
+         * the [.EXTRA_CHOSEN_WIFI_ENTRY_KEY].
+         *
+         *
+         * Output: Nothing.
+         */
+        @JvmField
+        @VisibleForTesting
+        val ACTION_WIFI_DIALOG = "com.android.settings.WIFI_DIALOG"
+
+        /**
+         * Specify a key that indicates the WifiEntry to be configured.
+         */
+        @JvmField
+        @VisibleForTesting
+        val EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key"
+
+        /**
+         * The lookup key for a boolean that indicates whether a chosen WifiEntry request to connect to.
+         * `true` means a chosen WifiEntry request to connect to.
+         */
+        @JvmField
+        @VisibleForTesting
+        val EXTRA_CONNECT_FOR_CALLER = "connect_for_caller"
+
+        /**
+         * The intent action shows network details settings to allow configuration of Wi-Fi.
+         *
+         *
+         * In some cases, a matching Activity may not exist, so ensure you
+         * safeguard against this.
+         *
+         *
+         * Input: The calling package should put the chosen
+         * com.android.wifitrackerlib.WifiEntry#getKey() to a string extra in the request bundle into
+         * the [.KEY_CHOSEN_WIFIENTRY_KEY].
+         *
+         *
+         * Output: Nothing.
+         */
+        const val ACTION_WIFI_DETAILS_SETTINGS = "android.settings.WIFI_DETAILS_SETTINGS"
+        const val KEY_CHOSEN_WIFIENTRY_KEY = "key_chosen_wifientry_key"
+        const val EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args"
+
+        @JvmField
+        val WIFI_PIE = getIconsBasedOnFlag()
+
+        private fun getIconsBasedOnFlag(): IntArray {
+            return if (newStatusBarIcons()) {
+                intArrayOf(
+                    R.drawable.ic_wifi_0,
+                    R.drawable.ic_wifi_1,
+                    R.drawable.ic_wifi_2,
+                    R.drawable.ic_wifi_3,
+                    R.drawable.ic_wifi_4
+                )
+            } else {
+                intArrayOf(
+                    com.android.internal.R.drawable.ic_wifi_signal_0,
+                    com.android.internal.R.drawable.ic_wifi_signal_1,
+                    com.android.internal.R.drawable.ic_wifi_signal_2,
+                    com.android.internal.R.drawable.ic_wifi_signal_3,
+                    com.android.internal.R.drawable.ic_wifi_signal_4
+                )
+            }
+        }
+
+        val NO_INTERNET_WIFI_PIE = getErrorIconsBasedOnFlag()
+
+        private fun getErrorIconsBasedOnFlag(): IntArray {
+            return if (newStatusBarIcons()) {
+                intArrayOf(
+                    R.drawable.ic_wifi_0_error,
+                    R.drawable.ic_wifi_1_error,
+                    R.drawable.ic_wifi_2_error,
+                    R.drawable.ic_wifi_3_error,
+                    R.drawable.ic_wifi_4_error
+                )
+            } else {
+                intArrayOf(
+                    R.drawable.ic_no_internet_wifi_signal_0,
+                    R.drawable.ic_no_internet_wifi_signal_1,
+                    R.drawable.ic_no_internet_wifi_signal_2,
+                    R.drawable.ic_no_internet_wifi_signal_3,
+                    R.drawable.ic_no_internet_wifi_signal_4
+                )
+            }
+        }
+
+        @JvmStatic
+        fun buildLoggingSummary(accessPoint: AccessPoint, config: WifiConfiguration?): String {
+            val summary = StringBuilder()
+            val info = accessPoint.info
+            // Add RSSI/band information for this config, what was seen up to 6 seconds ago
+            // verbose WiFi Logging is only turned on thru developers settings
+            if (accessPoint.isActive && info != null) {
+                summary.append(" f=" + info.frequency.toString())
+            }
+            summary.append(" " + getVisibilityStatus(accessPoint))
+            if (config != null && (config.networkSelectionStatus.networkSelectionStatus
+                    != NetworkSelectionStatus.NETWORK_SELECTION_ENABLED)
+            ) {
+                summary.append(" (" + config.networkSelectionStatus.networkStatusString)
+                if (config.networkSelectionStatus.disableTime > 0) {
+                    val now = System.currentTimeMillis()
+                    val diff = (now - config.networkSelectionStatus.disableTime) / 1000
+                    val sec = diff % 60 // seconds
+                    val min = diff / 60 % 60 // minutes
+                    val hour = min / 60 % 60 // hours
+                    summary.append(", ")
+                    if (hour > 0) summary.append(hour.toString() + "h ")
+                    summary.append(min.toString() + "m ")
+                    summary.append(sec.toString() + "s ")
+                }
+                summary.append(")")
+            }
+            if (config != null) {
+                val networkStatus = config.networkSelectionStatus
+                for (reason in 0..NetworkSelectionStatus.getMaxNetworkSelectionDisableReason()) {
+                    if (networkStatus.getDisableReasonCounter(reason) != 0) {
+                        summary.append(" ")
+                            .append(
+                                NetworkSelectionStatus
+                                    .getNetworkSelectionDisableReasonString(reason)
+                            )
+                            .append("=")
+                            .append(networkStatus.getDisableReasonCounter(reason))
+                    }
+                }
+            }
+            return summary.toString()
+        }
+
+        /**
+         * Returns the visibility status of the WifiConfiguration.
+         *
+         * @return autojoin debugging information
+         * TODO: use a string formatter
+         * ["rssi 5Ghz", "num results on 5GHz" / "rssi 5Ghz", "num results on 5GHz"]
+         * For instance [-40,5/-30,2]
+         */
+        @JvmStatic
+        @VisibleForTesting
+        fun getVisibilityStatus(accessPoint: AccessPoint): String {
+            val info = accessPoint.info
+            val visibility = StringBuilder()
+            val scans24GHz = StringBuilder()
+            val scans5GHz = StringBuilder()
+            val scans60GHz = StringBuilder()
+            var bssid: String? = null
+            if (accessPoint.isActive && info != null) {
+                bssid = info.bssid
+                if (bssid != null) {
+                    visibility.append(" ").append(bssid)
+                }
+                visibility.append(" standard = ").append(info.wifiStandard)
+                visibility.append(" rssi=").append(info.rssi)
+                visibility.append(" ")
+                visibility.append(" score=").append(info.getScore())
+                if (accessPoint.speed != AccessPoint.Speed.NONE) {
+                    visibility.append(" speed=").append(accessPoint.speedLabel)
+                }
+                visibility.append(String.format(" tx=%.1f,", info.successfulTxPacketsPerSecond))
+                visibility.append(String.format("%.1f,", info.retriedTxPacketsPerSecond))
+                visibility.append(String.format("%.1f ", info.lostTxPacketsPerSecond))
+                visibility.append(String.format("rx=%.1f", info.successfulRxPacketsPerSecond))
+            }
+            var maxRssi5 = INVALID_RSSI
+            var maxRssi24 = INVALID_RSSI
+            var maxRssi60 = INVALID_RSSI
+            val maxDisplayedScans = 4
+            var num5 = 0 // number of scanned BSSID on 5GHz band
+            var num24 = 0 // number of scanned BSSID on 2.4Ghz band
+            var num60 = 0 // number of scanned BSSID on 60Ghz band
+            val numBlockListed = 0
+
+            // TODO: sort list by RSSI or age
+            val nowMs = SystemClock.elapsedRealtime()
+            for (result in accessPoint.getScanResults()) {
+                if (result == null) {
+                    continue
+                }
+                if (result.frequency >= AccessPoint.LOWER_FREQ_5GHZ &&
+                    result.frequency <= AccessPoint.HIGHER_FREQ_5GHZ
+                ) {
+                    // Strictly speaking: [4915, 5825]
+                    num5++
+                    if (result.level > maxRssi5) {
+                        maxRssi5 = result.level
+                    }
+                    if (num5 <= maxDisplayedScans) {
+                        scans5GHz.append(
+                            verboseScanResultSummary(
+                                accessPoint, result, bssid,
+                                nowMs
+                            )
+                        )
+                    }
+                } else if (result.frequency >= AccessPoint.LOWER_FREQ_24GHZ &&
+                    result.frequency <= AccessPoint.HIGHER_FREQ_24GHZ
+                ) {
+                    // Strictly speaking: [2412, 2482]
+                    num24++
+                    if (result.level > maxRssi24) {
+                        maxRssi24 = result.level
+                    }
+                    if (num24 <= maxDisplayedScans) {
+                        scans24GHz.append(
+                            verboseScanResultSummary(
+                                accessPoint, result, bssid,
+                                nowMs
+                            )
+                        )
+                    }
+                } else if (result.frequency >= AccessPoint.LOWER_FREQ_60GHZ &&
+                    result.frequency <= AccessPoint.HIGHER_FREQ_60GHZ
+                ) {
+                    // Strictly speaking: [60000, 61000]
+                    num60++
+                    if (result.level > maxRssi60) {
+                        maxRssi60 = result.level
+                    }
+                    if (num60 <= maxDisplayedScans) {
+                        scans60GHz.append(
+                            verboseScanResultSummary(
+                                accessPoint, result, bssid,
+                                nowMs
+                            )
+                        )
+                    }
+                }
+            }
+            visibility.append(" [")
+            if (num24 > 0) {
+                visibility.append("(").append(num24).append(")")
+                if (num24 > maxDisplayedScans) {
+                    visibility.append("max=").append(maxRssi24).append(",")
+                }
+                visibility.append(scans24GHz.toString())
+            }
+            visibility.append(";")
+            if (num5 > 0) {
+                visibility.append("(").append(num5).append(")")
+                if (num5 > maxDisplayedScans) {
+                    visibility.append("max=").append(maxRssi5).append(",")
+                }
+                visibility.append(scans5GHz.toString())
+            }
+            visibility.append(";")
+            if (num60 > 0) {
+                visibility.append("(").append(num60).append(")")
+                if (num60 > maxDisplayedScans) {
+                    visibility.append("max=").append(maxRssi60).append(",")
+                }
+                visibility.append(scans60GHz.toString())
+            }
+            if (numBlockListed > 0) {
+                visibility.append("!").append(numBlockListed)
+            }
+            visibility.append("]")
+            return visibility.toString()
+        }
+
+        @JvmStatic
+        @VisibleForTesting /* package */ fun verboseScanResultSummary(
+            accessPoint: AccessPoint,
+            result: ScanResult,
+            bssid: String?,
+            nowMs: Long
+        ): String {
+            val stringBuilder = StringBuilder()
+            stringBuilder.append(" \n{").append(result.BSSID)
+            if (result.BSSID == bssid) {
+                stringBuilder.append("*")
+            }
+            stringBuilder.append("=").append(result.frequency)
+            stringBuilder.append(",").append(result.level)
+            val speed = getSpecificApSpeed(result, accessPoint.scoredNetworkCache)
+            if (speed != AccessPoint.Speed.NONE) {
+                stringBuilder.append(",")
+                    .append(accessPoint.getSpeedLabel(speed))
+            }
+            val ageSeconds = (nowMs - result.timestamp / 1000).toInt() / 1000
+            stringBuilder.append(",").append(ageSeconds).append("s")
+            stringBuilder.append("}")
+            return stringBuilder.toString()
+        }
+
+        @AccessPoint.Speed
+        private fun getSpecificApSpeed(
+            result: ScanResult,
+            scoredNetworkCache: Map<String, TimestampedScoredNetwork>
+        ): Int {
+            val timedScore = scoredNetworkCache[result.BSSID] ?: return AccessPoint.Speed.NONE
+            // For debugging purposes we may want to use mRssi rather than result.level as the average
+            // speed wil be determined by mRssi
+            return timedScore.score.calculateBadge(result.level)
+        }
+
+        @JvmStatic
+        fun getMeteredLabel(context: Context, config: WifiConfiguration): String {
+            // meteredOverride is whether the user manually set the metered setting or not.
+            // meteredHint is whether the network itself is telling us that it is metered
+            return if (config.meteredOverride == WifiConfiguration.METERED_OVERRIDE_METERED ||
+                config.meteredHint && !isMeteredOverridden(
+                    config
+                )
+            ) {
+                context.getString(R.string.wifi_metered_label)
+            } else context.getString(R.string.wifi_unmetered_label)
+        }
+
+        /**
+         * Returns the Internet icon resource for a given RSSI level.
+         *
+         * @param level The number of bars to show (0-4)
+         * @param noInternet True if a connected Wi-Fi network cannot access the Internet
+         */
+        @JvmStatic
+        fun getInternetIconResource(level: Int, noInternet: Boolean): Int {
+            var wifiLevel = level
+            if (wifiLevel < 0) {
+                Log.e(TAG, "Wi-Fi level is out of range! level:$level")
+                wifiLevel = 0
+            } else if (level >= WIFI_PIE.size) {
+                Log.e(TAG, "Wi-Fi level is out of range! level:$level")
+                wifiLevel = WIFI_PIE.size - 1
+            }
+            return if (noInternet) NO_INTERNET_WIFI_PIE[wifiLevel] else WIFI_PIE[wifiLevel]
+        }
+
+        /**
+         * Returns the Hotspot network icon resource.
+         *
+         * @param deviceType The device type of Hotspot network
+         */
+        @JvmStatic
+        fun getHotspotIconResource(deviceType: Int): Int {
+            return when (deviceType) {
+                NetworkProviderInfo.DEVICE_TYPE_PHONE -> R.drawable.ic_hotspot_phone
+                NetworkProviderInfo.DEVICE_TYPE_TABLET -> R.drawable.ic_hotspot_tablet
+                NetworkProviderInfo.DEVICE_TYPE_LAPTOP -> R.drawable.ic_hotspot_laptop
+                NetworkProviderInfo.DEVICE_TYPE_WATCH -> R.drawable.ic_hotspot_watch
+                NetworkProviderInfo.DEVICE_TYPE_AUTO -> R.drawable.ic_hotspot_auto
+                else -> R.drawable.ic_hotspot_phone
+            }
+        }
+
+        @JvmStatic
+        fun isMeteredOverridden(config: WifiConfiguration): Boolean {
+            return config.meteredOverride != WifiConfiguration.METERED_OVERRIDE_NONE
+        }
+
+        /**
+         * Returns the Intent for Wi-Fi dialog.
+         *
+         * @param key              The Wi-Fi entry key
+         * @param connectForCaller True if a chosen WifiEntry request to connect to
+         */
+        @JvmStatic
+        fun getWifiDialogIntent(key: String?, connectForCaller: Boolean): Intent {
+            val intent = Intent(ACTION_WIFI_DIALOG)
+            intent.putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, key)
+            intent.putExtra(EXTRA_CONNECT_FOR_CALLER, connectForCaller)
+            return intent
+        }
+
+        /**
+         * Returns the Intent for Wi-Fi network details settings.
+         *
+         * @param key The Wi-Fi entry key
+         */
+        @JvmStatic
+        fun getWifiDetailsSettingsIntent(key: String?): Intent {
+            val intent = Intent(ACTION_WIFI_DETAILS_SETTINGS)
+            val bundle = Bundle()
+            bundle.putString(KEY_CHOSEN_WIFIENTRY_KEY, key)
+            intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, bundle)
+            return intent
+        }
+
+        /**
+         * Returns the string of Wi-Fi tethering summary for connected devices.
+         *
+         * @param context          The application context
+         * @param connectedDevices The count of connected devices
+         */
+        @JvmStatic
+        fun getWifiTetherSummaryForConnectedDevices(
+            context: Context,
+            connectedDevices: Int
+        ): String {
+            val msgFormat = MessageFormat(
+                context.resources.getString(R.string.wifi_tether_connected_summary),
+                Locale.getDefault()
+            )
+            val arguments: MutableMap<String, Any> = HashMap()
+            arguments["count"] = connectedDevices
+            return msgFormat.format(arguments)
+        }
+
+        @JvmStatic
+        fun checkWepAllowed(
+            context: Context,
+            lifecycleOwner: LifecycleOwner,
+            ssid: String,
+            onAllowed: () -> Unit,
+        ) {
+            lifecycleOwner.lifecycleScope.launch {
+                val wifiManager = context.getSystemService(WifiManager::class.java) ?: return@launch
+                if (wifiManager.queryWepAllowed()) {
+                    onAllowed()
+                } else {
+                    val intent = Intent(Intent.ACTION_MAIN).apply {
+                        component = ComponentName(
+                            "com.android.settings",
+                            "com.android.settings.network.WepNetworkDialogActivity"
+                        )
+                        putExtra(SSID, ssid)
+                    }
+                    context.startActivity(intent)
+                }
+            }
+        }
+
+        private suspend fun WifiManager.queryWepAllowed(): Boolean =
+            withContext(Dispatchers.Default) {
+                suspendCancellableCoroutine { continuation ->
+                    queryWepAllowed(Dispatchers.Default.asExecutor()) {
+                        continuation.resume(it)
+                    }
+                }
+            }
+
+        const val SSID = "ssid"
+    }
+}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/FakeSpatializerRepository.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/FakeSpatializerRepository.kt
deleted file mode 100644
index 3f52f24..0000000
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/FakeSpatializerRepository.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package com.android.settingslib.media.domain.interactor
-
-import android.media.AudioDeviceAttributes
-import com.android.settingslib.media.data.repository.SpatializerRepository
-
-class FakeSpatializerRepository : SpatializerRepository {
-
-    private val availabilityByDevice: MutableMap<AudioDeviceAttributes, Boolean> = mutableMapOf()
-    private val compatibleDevices: MutableList<AudioDeviceAttributes> = mutableListOf()
-
-    override suspend fun isAvailableForDevice(
-        audioDeviceAttributes: AudioDeviceAttributes
-    ): Boolean = availabilityByDevice.getOrDefault(audioDeviceAttributes, false)
-
-    override suspend fun getCompatibleDevices(): Collection<AudioDeviceAttributes> =
-        compatibleDevices
-
-    override suspend fun addCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) {
-        compatibleDevices.add(audioDeviceAttributes)
-    }
-
-    override suspend fun removeCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) {
-        compatibleDevices.remove(audioDeviceAttributes)
-    }
-
-    fun setIsAvailable(audioDeviceAttributes: AudioDeviceAttributes, isAvailable: Boolean) {
-        availabilityByDevice[audioDeviceAttributes] = isAvailable
-    }
-}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/SpatializerInteractorTest.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/SpatializerInteractorTest.kt
deleted file mode 100644
index a44baeb..0000000
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/SpatializerInteractorTest.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package com.android.settingslib.media.domain.interactor
-
-import android.media.AudioDeviceAttributes
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runTest
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class SpatializerInteractorTest {
-
-    private val testScope = TestScope()
-    private val underTest = SpatializerInteractor(FakeSpatializerRepository())
-
-    @Test
-    fun setEnabledFalse_isEnabled_false() {
-        testScope.runTest {
-            underTest.setEnabled(deviceAttributes, false)
-
-            assertThat(underTest.isEnabled(deviceAttributes)).isFalse()
-        }
-    }
-
-    @Test
-    fun setEnabledTrue_isEnabled_true() {
-        testScope.runTest {
-            underTest.setEnabled(deviceAttributes, true)
-
-            assertThat(underTest.isEnabled(deviceAttributes)).isTrue()
-        }
-    }
-
-    private companion object {
-        val deviceAttributes = AudioDeviceAttributes(0, 0, "test_device")
-    }
-}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppCopyingHelperTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppCopyingHelperTest.java
index 2a5c43c..9ab17c4 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppCopyingHelperTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppCopyingHelperTest.java
@@ -37,9 +37,10 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.os.UserHandle;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArraySet;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.settingslib.BaseTest;
 
 import org.mockito.ArgumentMatcher;
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
index 2522e95..ab28d06 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
@@ -41,9 +41,10 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.inputmethod.InputMethodInfo;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.settingslib.BaseTest;
 
 import org.mockito.ArgumentMatcher;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 461ecf5d..5996dbb 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -18,9 +18,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -58,8 +56,6 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.shadow.api.Shadow;
 
-import java.util.concurrent.ExecutionException;
-
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {ShadowBluetoothAdapter.class})
 public class CachedBluetoothDeviceTest {
@@ -1823,52 +1819,6 @@
         assertThat(mCachedDevice.isConnectedHearingAidDevice()).isFalse();
     }
 
-    @Test
-    public void syncProfileForMemberDevice_hasDiff_shouldSync()
-            throws ExecutionException, InterruptedException {
-        mCachedDevice.addMemberDevice(mSubCachedDevice);
-        when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
-        when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
-        when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
-
-        when(mA2dpProfile.isEnabled(mDevice)).thenReturn(true);
-        when(mHearingAidProfile.isEnabled(mDevice)).thenReturn(true);
-        when(mLeAudioProfile.isEnabled(mDevice)).thenReturn(true);
-
-        when(mA2dpProfile.isEnabled(mSubDevice)).thenReturn(true);
-        when(mHearingAidProfile.isEnabled(mSubDevice)).thenReturn(false);
-        when(mLeAudioProfile.isEnabled(mSubDevice)).thenReturn(false);
-
-        mCachedDevice.syncProfileForMemberDevice().get();
-
-        verify(mA2dpProfile, never()).setEnabled(any(BluetoothDevice.class), anyBoolean());
-        verify(mHearingAidProfile).setEnabled(any(BluetoothDevice.class), eq(true));
-        verify(mLeAudioProfile).setEnabled(any(BluetoothDevice.class), eq(true));
-    }
-
-    @Test
-    public void syncProfileForMemberDevice_noDiff_shouldNotSync()
-            throws ExecutionException, InterruptedException {
-        mCachedDevice.addMemberDevice(mSubCachedDevice);
-        when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
-        when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
-        when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
-
-        when(mA2dpProfile.isEnabled(mDevice)).thenReturn(false);
-        when(mHearingAidProfile.isEnabled(mDevice)).thenReturn(false);
-        when(mLeAudioProfile.isEnabled(mDevice)).thenReturn(true);
-
-        when(mA2dpProfile.isEnabled(mSubDevice)).thenReturn(false);
-        when(mHearingAidProfile.isEnabled(mSubDevice)).thenReturn(false);
-        when(mLeAudioProfile.isEnabled(mSubDevice)).thenReturn(true);
-
-        mCachedDevice.syncProfileForMemberDevice().get();
-
-        verify(mA2dpProfile, never()).setEnabled(any(BluetoothDevice.class), anyBoolean());
-        verify(mHearingAidProfile, never()).setEnabled(any(BluetoothDevice.class), anyBoolean());
-        verify(mLeAudioProfile, never()).setEnabled(any(BluetoothDevice.class), anyBoolean());
-    }
-
     private HearingAidInfo getLeftAshaHearingAidInfo() {
         return new HearingAidInfo.Builder()
                 .setAshaDeviceSide(HearingAidProfile.DeviceSide.SIDE_LEFT)
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java
index 3705267..70ba415 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java
@@ -20,9 +20,7 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
 
 import android.annotation.SuppressLint;
 import android.content.Context;
@@ -94,19 +92,6 @@
     }
 
     @Test
-    public void updateConnectivity_notAvailable_notCalled() {
-        boolean mCalled = false;
-        mController = spy(new ConcreteWifiMacAddressPreferenceController(mContext, mLifecycle) {
-            @Override
-            public boolean isAvailable() {
-                return false;
-            }
-        });
-        mController.displayPreference(mScreen);
-        verify(mController, never()).updateConnectivity();
-    }
-
-    @Test
     public void updateConnectivity_null_setMacUnavailable() {
         doReturn(null).when(mWifiManager).getFactoryMacAddresses();
         mController.displayPreference(mScreen);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java
index 3b73192..c3237f0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java
@@ -16,7 +16,6 @@
 
 package com.android.settingslib.media;
 
-import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.verify;
@@ -32,6 +31,8 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
+import java.util.Collections;
+
 @RunWith(RobolectricTestRunner.class)
 public class MediaManagerTest {
 
@@ -52,24 +53,14 @@
 
         when(mDevice.getId()).thenReturn(TEST_ID);
 
-        mMediaManager = new MediaManager(mContext, null) {
-            @Override
-            public void startScan() {
-
-            }
-
-            @Override
-            public void stopScan() {
-
-            }
-        };
+        mMediaManager = new MediaManager(mContext, null) {};
     }
 
     @Test
     public void dispatchDeviceListAdded_registerCallback_shouldDispatchCallback() {
         mMediaManager.registerCallback(mCallback);
 
-        mMediaManager.dispatchDeviceListAdded();
+        mMediaManager.dispatchDeviceListAdded(Collections.emptyList());
 
         verify(mCallback).onDeviceListAdded(any());
     }
@@ -78,9 +69,9 @@
     public void dispatchDeviceListRemoved_registerCallback_shouldDispatchCallback() {
         mMediaManager.registerCallback(mCallback);
 
-        mMediaManager.dispatchDeviceListRemoved(mMediaManager.mMediaDevices);
+        mMediaManager.dispatchDeviceListRemoved(Collections.emptyList());
 
-        verify(mCallback).onDeviceListRemoved(mMediaManager.mMediaDevices);
+        verify(mCallback).onDeviceListRemoved(Collections.emptyList());
     }
 
     @Test
@@ -93,24 +84,6 @@
     }
 
     @Test
-    public void findMediaDevice_idExist_shouldReturnMediaDevice() {
-        mMediaManager.mMediaDevices.add(mDevice);
-
-        final MediaDevice device = mMediaManager.findMediaDevice(TEST_ID);
-
-        assertThat(device.getId()).isEqualTo(mDevice.getId());
-    }
-
-    @Test
-    public void findMediaDevice_idNotExist_shouldReturnNull() {
-        mMediaManager.mMediaDevices.add(mDevice);
-
-        final MediaDevice device = mMediaManager.findMediaDevice("123");
-
-        assertThat(device).isNull();
-    }
-
-    @Test
     public void dispatchOnRequestFailed_registerCallback_shouldDispatchCallback() {
         mMediaManager.registerCallback(mCallback);
 
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp
index d5814e3..94ea016 100644
--- a/packages/SettingsProvider/Android.bp
+++ b/packages/SettingsProvider/Android.bp
@@ -60,6 +60,7 @@
         // because this test is not an instrumentation test. (because the target runs in the system process.)
         "SettingsProviderLib",
         "androidx.test.rules",
+        "device_config_service_flags_java",
         "flag-junit",
         "junit",
         "libaconfig_java_proto_lite",
diff --git a/packages/SettingsProvider/res/xml/bookmarks.xml b/packages/SettingsProvider/res/xml/bookmarks.xml
index 4b97b47..22d0226 100644
--- a/packages/SettingsProvider/res/xml/bookmarks.xml
+++ b/packages/SettingsProvider/res/xml/bookmarks.xml
@@ -23,7 +23,7 @@
        'c': Contacts
        'e': Email
        'g': GMail
-       'l': Calendar
+       'k': Calendar
        'm': Maps
        'p': Music
        's': SMS
@@ -33,7 +33,7 @@
 -->
 <bookmarks>
     <bookmark
-        category="android.intent.category.APP_BROWSER"
+        role="android.app.role.BROWSER"
         shortcut="b" />
     <bookmark
         category="android.intent.category.APP_CONTACTS"
@@ -51,7 +51,7 @@
         category="android.intent.category.APP_MUSIC"
         shortcut="p" />
     <bookmark
-        category="android.intent.category.APP_MESSAGING"
+        role="android.app.role.SMS"
         shortcut="s" />
     <bookmark
         category="android.intent.category.APP_CALCULATOR"
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index e424797..a490b6f 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -154,6 +154,7 @@
         Settings.Secure.MANUAL_RINGER_TOGGLE_COUNT,
         Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
         Settings.Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED,
+        Settings.Secure.EMERGENCY_THERMAL_ALERT_DISABLED,
         Settings.Secure.HUSH_GESTURE_USED,
         Settings.Secure.IN_CALL_NOTIFICATION_ENABLED,
         Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
@@ -227,6 +228,7 @@
         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED,
         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
         Settings.Secure.ACCESSIBILITY_PINCH_TO_ZOOM_ANYWHERE_ENABLED,
+        Settings.Secure.ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED,
         Settings.Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED,
         Settings.Secure.NOTIFICATION_BUBBLES,
         Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index a32eead..4cdf98cb 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -235,6 +235,7 @@
         VALIDATORS.put(Secure.MANUAL_RINGER_TOGGLE_COUNT, NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(Secure.LOW_POWER_WARNING_ACKNOWLEDGED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.EMERGENCY_THERMAL_ALERT_DISABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.IN_CALL_NOTIFICATION_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, BOOLEAN_VALIDATOR);
@@ -321,6 +322,7 @@
                 Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
                 BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_PINCH_TO_ZOOM_ANYWHERE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(
                 Secure.ACCESSIBILITY_BUTTON_TARGETS,
                 ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index 6ff36d4..ad3eb92 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -20,8 +20,6 @@
 import static android.provider.Settings.Config.SYNC_DISABLED_MODE_PERSISTENT;
 import static android.provider.Settings.Config.SYNC_DISABLED_MODE_UNTIL_REBOOT;
 
-import static com.android.providers.settings.Flags.supportOverrides;
-
 import android.aconfig.Aconfig.parsed_flag;
 import android.aconfig.Aconfig.parsed_flags;
 import android.annotation.SuppressLint;
@@ -269,9 +267,9 @@
                 verb = CommandVerb.GET;
             } else if ("put".equalsIgnoreCase(cmd)) {
                 verb = CommandVerb.PUT;
-            } else if (supportOverrides() && "override".equalsIgnoreCase(cmd)) {
+            } else if ("override".equalsIgnoreCase(cmd)) {
                 verb = CommandVerb.OVERRIDE;
-            } else if (supportOverrides() && "clear_override".equalsIgnoreCase(cmd)) {
+            } else if ("clear_override".equalsIgnoreCase(cmd)) {
                 verb = CommandVerb.CLEAR_OVERRIDE;
             } else if ("delete".equalsIgnoreCase(cmd)) {
                 verb = CommandVerb.DELETE;
@@ -285,7 +283,7 @@
                 if (peekNextArg() == null) {
                     isValid = true;
                 }
-            } else if (supportOverrides() && "list_local_overrides".equalsIgnoreCase(cmd)) {
+            } else if ("list_local_overrides".equalsIgnoreCase(cmd)) {
                 verb = CommandVerb.LIST_LOCAL_OVERRIDES;
                 if (peekNextArg() == null) {
                     isValid = true;
@@ -427,14 +425,10 @@
                     DeviceConfig.setProperty(namespace, key, value, makeDefault);
                     break;
                 case OVERRIDE:
-                    if (supportOverrides()) {
-                        DeviceConfig.setLocalOverride(namespace, key, value);
-                    }
+                    DeviceConfig.setLocalOverride(namespace, key, value);
                     break;
                 case CLEAR_OVERRIDE:
-                    if (supportOverrides()) {
-                        DeviceConfig.clearLocalOverride(namespace, key);
-                    }
+                    DeviceConfig.clearLocalOverride(namespace, key);
                     break;
                 case DELETE:
                     pout.println(delete(iprovider, namespace, key)
@@ -452,19 +446,15 @@
                         }
                     } else {
                         for (String line : listAll(iprovider)) {
-                            if (supportOverrides()) {
-                                boolean isPrivate = false;
-                                for (String privateNamespace : PRIVATE_NAMESPACES) {
-                                    if (line.startsWith(privateNamespace)) {
-                                        isPrivate = true;
-                                        break;
-                                    }
+                            boolean isPrivate = false;
+                            for (String privateNamespace : PRIVATE_NAMESPACES) {
+                                if (line.startsWith(privateNamespace)) {
+                                    isPrivate = true;
+                                    break;
                                 }
+                            }
 
-                                if (!isPrivate) {
-                                    pout.println(line);
-                                }
-                            } else {
+                            if (!isPrivate) {
                                 pout.println(line);
                             }
                         }
@@ -495,18 +485,16 @@
                     }
                     break;
                 case LIST_LOCAL_OVERRIDES:
-                    if (supportOverrides()) {
-                        Map<String, Map<String, String>> underlyingValues =
-                                DeviceConfig.getUnderlyingValuesForOverriddenFlags();
-                        for (String overrideNamespace : underlyingValues.keySet()) {
-                            Map<String, String> flagToValue =
-                                    underlyingValues.get(overrideNamespace);
-                            for (String flag : flagToValue.keySet()) {
-                                String flagText = overrideNamespace + "/" + flag;
-                                String valueText =
-                                        DeviceConfig.getProperty(overrideNamespace, flag);
-                                pout.println(flagText + "=" + valueText);
-                            }
+                    Map<String, Map<String, String>> underlyingValues =
+                            DeviceConfig.getUnderlyingValuesForOverriddenFlags();
+                    for (String overrideNamespace : underlyingValues.keySet()) {
+                        Map<String, String> flagToValue =
+                                underlyingValues.get(overrideNamespace);
+                        for (String flag : flagToValue.keySet()) {
+                            String flagText = overrideNamespace + "/" + flag;
+                            String valueText =
+                                    DeviceConfig.getProperty(overrideNamespace, flag);
+                            pout.println(flagText + "=" + valueText);
                         }
                     }
                     break;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index d27ff17..02d212c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1865,6 +1865,10 @@
                 SecureSettingsProto.Accessibility
                         .ACCESSIBILITY_PINCH_TO_ZOOM_ANYWHERE_ENABLED);
         dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED,
+                SecureSettingsProto.Accessibility
+                        .ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED);
+        dumpSetting(s, p,
                 Settings.Secure.HEARING_AID_RINGTONE_ROUTING,
                 SecureSettingsProto.Accessibility.HEARING_AID_RINGTONE_ROUTING);
         dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index febce97..1ead14a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3812,7 +3812,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 225;
+            private static final int SETTINGS_VERSION = 226;
 
             private final int mUserId;
 
@@ -6011,6 +6011,28 @@
                     currentVersion = 225;
                 }
 
+                // Version 225: Set the System#KEYBOARD_VIBRATION_ENABLED based on touch
+                // feedback enabled state.
+                if (currentVersion == 225) {
+                    final SettingsState systemSettings = getSystemSettingsLocked(userId);
+                    final Setting touchFeedbackSettings = systemSettings
+                            .getSettingLocked(Settings.System.HAPTIC_FEEDBACK_ENABLED);
+                    final Setting keyboardVibrationSettings = systemSettings
+                            .getSettingLocked(Settings.System.KEYBOARD_VIBRATION_ENABLED);
+                    if (keyboardVibrationSettings.isNull()) {
+                        if (!touchFeedbackSettings.isNull()) {
+                            // Use touch feedback settings.
+                            systemSettings.insertSettingOverrideableByRestoreLocked(
+                                    Settings.System.KEYBOARD_VIBRATION_ENABLED,
+                                    touchFeedbackSettings.getValue(),
+                                    touchFeedbackSettings.getTag(),
+                                    touchFeedbackSettings.isDefaultFromSystem(),
+                                    SettingsState.SYSTEM_PACKAGE_NAME);
+                        }
+                    }
+                    currentVersion = 226;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 1c9e748..ce0257f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -359,6 +359,15 @@
 
     @VisibleForTesting
     @GuardedBy("mLock")
+    public void addAconfigDefaultValuesFromMap(
+            @NonNull Map<String, Map<String, String>> defaultMap) {
+        if (mNamespaceDefaults != null) {
+            mNamespaceDefaults.putAll(defaultMap);
+        }
+    }
+
+    @VisibleForTesting
+    @GuardedBy("mLock")
     public static void loadAconfigDefaultValues(byte[] fileContents,
             @NonNull Map<String, Map<String, String>> defaultMap) {
         try {
@@ -510,6 +519,28 @@
             return false;
         }
 
+        // Aconfig flags are always boot stable, so we anytime we write one, we staged it to be
+        // applied on reboot.
+        if (Flags.stageAllAconfigFlags() && mNamespaceDefaults != null) {
+            int slashIndex = name.indexOf("/");
+            boolean stageFlag = isConfigSettingsKey(mKey)
+                    && slashIndex != -1
+                    && slashIndex != 0
+                    && slashIndex != name.length();
+
+            if (stageFlag) {
+                String namespace = name.substring(0, slashIndex);
+                String flag = name.substring(slashIndex + 1);
+
+                boolean isAconfig = mNamespaceDefaults.containsKey(namespace)
+                        && mNamespaceDefaults.get(namespace).containsKey(name);
+
+                if (isAconfig) {
+                    name = "staged/" + namespace + "*" + flag;
+                }
+            }
+        }
+
         final boolean isNameTooLong = name.length() > SettingsState.MAX_LENGTH_PER_STRING;
         final boolean isValueTooLong =
                 value != null && value.length() > SettingsState.MAX_LENGTH_PER_STRING;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig b/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig
index ecac5ee..e5086e8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig
+++ b/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig
@@ -14,3 +14,14 @@
     bug: "311155098"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "stage_all_aconfig_flags"
+    namespace: "core_experiments_team_internal"
+    description: "Stage _all_ aconfig flags on writes, even local ones."
+    bug: "326598713"
+    is_fixed_read_only: true
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index 9ecbd50..ea30c69 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -15,13 +15,25 @@
  */
 package com.android.providers.settings;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
 import android.aconfig.Aconfig;
 import android.aconfig.Aconfig.parsed_flag;
 import android.aconfig.Aconfig.parsed_flags;
 import android.os.Looper;
-import android.test.AndroidTestCase;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.util.Xml;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.modules.utils.TypedXmlSerializer;
 
 import com.google.common.base.Strings;
@@ -34,7 +46,18 @@
 import java.util.List;
 import java.util.Map;
 
-public class SettingsStateTest extends AndroidTestCase {
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class SettingsStateTest {
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
+
     public static final String CRAZY_STRING =
             "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\n\u000b\u000c\r" +
                     "\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a" +
@@ -76,25 +99,25 @@
 
     private File mSettingsFile;
 
-    @Override
-    protected void setUp() {
-        mSettingsFile = new File(getContext().getCacheDir(), "setting.xml");
+    @Before
+    public void setUp() {
+        mSettingsFile = new File(InstrumentationRegistry.getContext().getCacheDir(), "setting.xml");
         mSettingsFile.delete();
     }
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void tearDown() throws Exception {
         if (mSettingsFile != null) {
             mSettingsFile.delete();
         }
-        super.tearDown();
     }
 
+    @Test
     public void testLoadValidAconfigProto() {
         int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0);
         Object lock = new Object();
         SettingsState settingsState = new SettingsState(
-                getContext(), lock, mSettingsFile, configKey,
+                InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey,
                 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
         parsed_flags flags = parsed_flags
                 .newBuilder()
@@ -129,11 +152,12 @@
         }
     }
 
+    @Test
     public void testSkipLoadingAconfigFlagWithMissingFields() {
         int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0);
         Object lock = new Object();
         SettingsState settingsState = new SettingsState(
-                getContext(), lock, mSettingsFile, configKey,
+                InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey,
                 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
 
         parsed_flags flags = parsed_flags
@@ -155,12 +179,97 @@
         }
     }
 
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_STAGE_ALL_ACONFIG_FLAGS)
+    public void testWritingAconfigFlagStages() {
+        int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0);
+        Object lock = new Object();
+        SettingsState settingsState = new SettingsState(
+                InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey,
+                SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+        parsed_flags flags = parsed_flags
+                .newBuilder()
+                .addParsedFlag(parsed_flag
+                    .newBuilder()
+                        .setPackage("com.android.flags")
+                        .setName("flag5")
+                        .setNamespace("test_namespace")
+                        .setDescription("test flag")
+                        .addBug("12345678")
+                        .setState(Aconfig.flag_state.DISABLED)
+                        .setPermission(Aconfig.flag_permission.READ_WRITE))
+                .build();
+
+        synchronized (lock) {
+            Map<String, Map<String, String>> defaults = new HashMap<>();
+            settingsState.loadAconfigDefaultValues(flags.toByteArray(), defaults);
+            settingsState.addAconfigDefaultValuesFromMap(defaults);
+
+            settingsState.insertSettingLocked("test_namespace/com.android.flags.flag5",
+                    "true", null, false, "com.android.flags");
+            settingsState.insertSettingLocked("test_namespace/com.android.flags.flag6",
+                    "true", null, false, "com.android.flags");
+
+            assertEquals("true",
+                    settingsState
+                        .getSettingLocked("staged/test_namespace*com.android.flags.flag5")
+                        .getValue());
+            assertEquals(null,
+                    settingsState
+                        .getSettingLocked("test_namespace/com.android.flags.flag5")
+                        .getValue());
+
+            assertEquals(null,
+                    settingsState
+                        .getSettingLocked("staged/test_namespace*com.android.flags.flag6")
+                        .getValue());
+            assertEquals("true",
+                    settingsState
+                        .getSettingLocked("test_namespace/com.android.flags.flag6")
+                        .getValue());
+        }
+    }
+
+    @Test
+    @RequiresFlagsDisabled(Flags.FLAG_LOAD_ACONFIG_DEFAULTS)
+    public void testAddingAconfigMapOnNullIsNoOp() {
+        int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0);
+        Object lock = new Object();
+        SettingsState settingsState = new SettingsState(
+                InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey,
+                SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+
+        parsed_flags flags = parsed_flags
+                .newBuilder()
+                .addParsedFlag(parsed_flag
+                    .newBuilder()
+                        .setPackage("com.android.flags")
+                        .setName("flag5")
+                        .setNamespace("test_namespace")
+                        .setDescription("test flag")
+                        .addBug("12345678")
+                        .setState(Aconfig.flag_state.DISABLED)
+                        .setPermission(Aconfig.flag_permission.READ_WRITE))
+                .build();
+
+        synchronized (lock) {
+            Map<String, Map<String, String>> defaults = new HashMap<>();
+            settingsState.loadAconfigDefaultValues(flags.toByteArray(), defaults);
+            settingsState.addAconfigDefaultValuesFromMap(defaults);
+
+            assertEquals(null, settingsState.getAconfigDefaultValues());
+        }
+
+    }
+
+    @Test
     public void testInvalidAconfigProtoDoesNotCrash() {
         Map<String, Map<String, String>> defaults = new HashMap<>();
         SettingsState settingsState = getSettingStateObject();
         settingsState.loadAconfigDefaultValues("invalid protobuf".getBytes(), defaults);
     }
 
+    @Test
     public void testIsBinary() {
         assertFalse(SettingsState.isBinary(" abc 日本語"));
 
@@ -191,6 +300,7 @@
     }
 
     /** Make sure we won't pass invalid characters to XML serializer. */
+    @Test
     public void testWriteReadNoCrash() throws Exception {
         ByteArrayOutputStream os = new ByteArrayOutputStream();
 
@@ -233,12 +343,15 @@
     /**
      * Make sure settings can be written to a file and also can be read.
      */
+    @Test
     public void testReadWrite() {
         final Object lock = new Object();
 
         assertFalse(mSettingsFile.exists());
-        final SettingsState ssWriter = new SettingsState(getContext(), lock, mSettingsFile, 1,
-                SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+        final SettingsState ssWriter =
+                new SettingsState(
+                        InstrumentationRegistry.getContext(), lock, mSettingsFile, 1,
+                        SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
         ssWriter.setVersionLocked(SettingsState.SETTINGS_VERSION_NEW_ENCODING);
 
         ssWriter.insertSettingLocked("k1", "\u0000", null, false, "package");
@@ -250,8 +363,10 @@
         }
         ssWriter.waitForHandler();
         assertTrue(mSettingsFile.exists());
-        final SettingsState ssReader = new SettingsState(getContext(), lock, mSettingsFile, 1,
-                SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+        final SettingsState ssReader =
+                new SettingsState(
+                        InstrumentationRegistry.getContext(), lock, mSettingsFile, 1,
+                        SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
 
         synchronized (lock) {
             assertEquals("\u0000", ssReader.getSettingLocked("k1").getValue());
@@ -264,6 +379,7 @@
     /**
      * In version 120, value "null" meant {code NULL}.
      */
+    @Test
     public void testUpgrade() throws Exception {
         final Object lock = new Object();
         final PrintStream os = new PrintStream(new FileOutputStream(mSettingsFile));
@@ -276,8 +392,10 @@
                         "</settings>");
         os.close();
 
-        final SettingsState ss = new SettingsState(getContext(), lock, mSettingsFile, 1,
-                SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+        final SettingsState ss =
+                new SettingsState(
+                        InstrumentationRegistry.getContext(), lock, mSettingsFile, 1,
+                        SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
         synchronized (lock) {
             SettingsState.Setting s;
             s = ss.getSettingLocked("k0");
@@ -294,6 +412,7 @@
         }
     }
 
+    @Test
     public void testInitializeSetting_preserveFlagNotSet() {
         SettingsState settingsWriter = getSettingStateObject();
         settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE);
@@ -304,6 +423,7 @@
         assertFalse(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore());
     }
 
+    @Test
     public void testModifySetting_preserveFlagSet() {
         SettingsState settingsWriter = getSettingStateObject();
         settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE);
@@ -315,6 +435,7 @@
         assertTrue(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore());
     }
 
+    @Test
     public void testModifySettingOverrideableByRestore_preserveFlagNotSet() {
         SettingsState settingsWriter = getSettingStateObject();
         settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE);
@@ -327,6 +448,7 @@
         assertFalse(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore());
     }
 
+    @Test
     public void testModifySettingOverrideableByRestore_preserveFlagAlreadySet_flagValueUnchanged() {
         SettingsState settingsWriter = getSettingStateObject();
         // Init the setting.
@@ -344,6 +466,7 @@
         assertTrue(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore());
     }
 
+    @Test
     public void testResetSetting_preservedFlagIsReset() {
         SettingsState settingsState = getSettingStateObject();
         // Initialize the setting.
@@ -356,6 +479,7 @@
 
     }
 
+    @Test
     public void testModifySettingBySystemPackage_sameValue_preserveFlagNotSet() {
         SettingsState settingsState = getSettingStateObject();
         // Initialize the setting.
@@ -366,6 +490,7 @@
         assertFalse(settingsState.getSettingLocked(SETTING_NAME).isValuePreservedInRestore());
     }
 
+    @Test
     public void testModifySettingBySystemPackage_newValue_preserveFlagSet() {
         SettingsState settingsState = getSettingStateObject();
         // Initialize the setting.
@@ -377,12 +502,15 @@
     }
 
     private SettingsState getSettingStateObject() {
-        SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
-                SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+        SettingsState settingsState =
+                new SettingsState(
+                        InstrumentationRegistry.getContext(), mLock, mSettingsFile, 1,
+                        SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
         settingsState.setVersionLocked(SettingsState.SETTINGS_VERSION_NEW_ENCODING);
         return settingsState;
     }
 
+    @Test
     public void testInsertSetting_memoryUsage() {
         SettingsState settingsState = getSettingStateObject();
         // No exception should be thrown when there is no cap
@@ -390,8 +518,10 @@
                 null, false, "p1");
         settingsState.deleteSettingLocked(SETTING_NAME);
 
-        settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
-                SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper());
+        settingsState =
+                new SettingsState(
+                        InstrumentationRegistry.getContext(), mLock, mSettingsFile, 1,
+                        SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper());
         // System package doesn't have memory usage limit
         settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001),
                 null, false, SYSTEM_PACKAGE);
@@ -425,9 +555,12 @@
         }
     }
 
+    @Test
     public void testMemoryUsagePerPackage() {
-        SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
-                SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper());
+        SettingsState settingsState =
+                new SettingsState(
+                        InstrumentationRegistry.getContext(), mLock, mSettingsFile, 1,
+                        SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper());
 
         // Test inserting one key with default
         final String testKey1 = SETTING_NAME;
@@ -512,9 +645,12 @@
         assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE));
     }
 
+    @Test
     public void testLargeSettingKey() {
-        SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
-                SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper());
+        SettingsState settingsState =
+                new SettingsState(
+                        InstrumentationRegistry.getContext(), mLock, mSettingsFile, 1,
+                        SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper());
         final String largeKey = Strings.repeat("A", SettingsState.MAX_LENGTH_PER_STRING + 1);
         final String testValue = "testValue";
         synchronized (mLock) {
@@ -535,9 +671,12 @@
         }
     }
 
+    @Test
     public void testLargeSettingValue() {
-        SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
-                SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+        SettingsState settingsState =
+                new SettingsState(
+                        InstrumentationRegistry.getContext(), mLock, mSettingsFile, 1,
+                        SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
         final String testKey = "testKey";
         final String largeValue = Strings.repeat("A", SettingsState.MAX_LENGTH_PER_STRING + 1);
         synchronized (mLock) {
@@ -558,11 +697,12 @@
         }
     }
 
+    @Test
     public void testApplyStagedConfigValues() {
         int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0);
         Object lock = new Object();
         SettingsState settingsState = new SettingsState(
-                getContext(), lock, mSettingsFile, configKey,
+                InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey,
                 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
 
         synchronized (lock) {
@@ -578,7 +718,8 @@
             assertEquals(VALUE2, settingsState.getSettingLocked(FLAG_NAME_2).getValue());
         }
 
-        settingsState = new SettingsState(getContext(), lock, mSettingsFile, configKey,
+        settingsState = new SettingsState(
+                InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey,
                 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
 
         synchronized (lock) {
@@ -589,6 +730,7 @@
         }
     }
 
+    @Test
     public void testStagingTransformation() {
         assertEquals(INVALID_STAGED_FLAG_1,
                 SettingsState.createRealFlagName(INVALID_STAGED_FLAG_1));
@@ -603,11 +745,12 @@
                 SettingsState.createRealFlagName(VALID_STAGED_FLAG_1));
     }
 
+    @Test
     public void testInvalidStagedFlagsUnaffectedByReboot() {
         int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0);
         Object lock = new Object();
         SettingsState settingsState = new SettingsState(
-                getContext(), lock, mSettingsFile, configKey,
+                InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey,
                 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
 
         synchronized (lock) {
@@ -620,7 +763,8 @@
             assertEquals(VALUE2, settingsState.getSettingLocked(INVALID_STAGED_FLAG_1).getValue());
         }
 
-        settingsState = new SettingsState(getContext(), lock, mSettingsFile, configKey,
+        settingsState = new SettingsState(
+                InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey,
                 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
 
         synchronized (lock) {
@@ -628,6 +772,7 @@
         }
     }
 
+    @Test
     public void testsetSettingsLockedKeepTrunkDefault() throws Exception {
         final PrintStream os = new PrintStream(new FileOutputStream(mSettingsFile));
         os.print(
@@ -648,7 +793,7 @@
         int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0);
 
         SettingsState settingsState = new SettingsState(
-                getContext(), mLock, mSettingsFile, configKey,
+                InstrumentationRegistry.getContext(), mLock, mSettingsFile, configKey,
                 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
 
         String prefix = "test_namespace";
@@ -705,6 +850,7 @@
         }
     }
 
+    @Test
     public void testsetSettingsLockedNoTrunkDefault() throws Exception {
         final PrintStream os = new PrintStream(new FileOutputStream(mSettingsFile));
         os.print(
@@ -720,7 +866,7 @@
         int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0);
 
         SettingsState settingsState = new SettingsState(
-                getContext(), mLock, mSettingsFile, configKey,
+                InstrumentationRegistry.getContext(), mLock, mSettingsFile, configKey,
                 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
 
         Map<String, String> keyValues =
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 53f2caf..0c02f56 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -210,6 +210,7 @@
     <uses-permission android:name="android.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS" />
     <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" />
     <uses-permission android:name="android.permission.WHITELIST_RESTRICTED_PERMISSIONS" />
+    <uses-permission android:name="android.permission.EMERGENCY_INSTALL_PACKAGES" />
     <!-- Permission required for processes that don't own the focused window to switch
          touch mode state -->
     <uses-permission android:name="android.permission.MODIFY_TOUCH_MODE_STATE" />
diff --git a/packages/Shell/tests/src/com/android/shell/UtilitiesTest.java b/packages/Shell/tests/src/com/android/shell/UtilitiesTest.java
index 51b7ba8..ad9eec7 100644
--- a/packages/Shell/tests/src/com/android/shell/UtilitiesTest.java
+++ b/packages/Shell/tests/src/com/android/shell/UtilitiesTest.java
@@ -15,10 +15,12 @@
  */
 package com.android.shell;
 
-import android.test.suitebuilder.annotation.SmallTest;
-import junit.framework.TestCase;
 import static com.android.shell.BugreportProgressService.isValid;
 
+import androidx.test.filters.SmallTest;
+
+import junit.framework.TestCase;
+
 @SmallTest
 public class UtilitiesTest extends TestCase {
 
diff --git a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
index ea46c0c..ee81813 100644
--- a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
+++ b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
@@ -300,6 +300,8 @@
                 }
             };
             installTask.execute(data.getData());
+        } else if (requestCode == ADD_FILE_REQUEST_CODE && resultCode == RESULT_CANCELED) {
+            setupAlert();
         }
     }
 
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index d1a3571..cc2e84c 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -32,55 +32,6 @@
     ],
 }
 
-// Opt-in configuration for code depending on Jetpack Compose.
-soong_config_module_type {
-    name: "systemui_compose_java_defaults",
-    module_type: "java_defaults",
-    config_namespace: "ANDROID",
-    bool_variables: ["SYSTEMUI_USE_COMPOSE"],
-    properties: [
-        "srcs",
-        "static_libs",
-    ],
-}
-
-systemui_compose_java_defaults {
-    name: "SystemUI_compose_defaults",
-    soong_config_variables: {
-        SYSTEMUI_USE_COMPOSE: {
-            // Because files in compose/features/ depend on SystemUI
-            // code, we compile those files when compiling SystemUI-core.
-            // We also compile the ComposeFacade in
-            // compose/facade/enabled/.
-            srcs: [
-                "compose/features/src/**/*.kt",
-                "compose/facade/enabled/src/**/*.kt",
-            ],
-
-            // The dependencies needed by SystemUIComposeFeatures,
-            // except for SystemUI-core.
-            // Copied from compose/features/Android.bp.
-            static_libs: [
-                "PlatformComposeCore",
-                "PlatformComposeSceneTransitionLayout",
-
-                "androidx.compose.runtime_runtime",
-                "androidx.compose.material3_material3",
-                "androidx.compose.material_material-icons-extended",
-                "androidx.activity_activity-compose",
-                "androidx.compose.animation_animation-graphics",
-            ],
-
-            // By default, Compose is disabled and we compile the ComposeFacade
-            // in compose/facade/disabled/.
-            conditions_default: {
-                srcs: ["compose/facade/disabled/src/**/*.kt"],
-                static_libs: [],
-            },
-        },
-    },
-}
-
 java_library {
     name: "SystemUI-proto",
 
@@ -138,14 +89,13 @@
 
 android_library {
     name: "SystemUI-core",
-    defaults: [
-        "SystemUI_compose_defaults",
-    ],
     srcs: [
         "src/**/*.kt",
         "src/**/*.java",
         "src/**/I*.aidl",
         ":ReleaseJavaFiles",
+        "compose/features/src/**/*.kt",
+        "compose/facade/enabled/src/**/*.kt",
     ],
     product_variables: {
         debuggable: {
@@ -207,6 +157,13 @@
         "LowLightDreamLib",
         "motion_tool_lib",
         "notification_flags_lib",
+        "PlatformComposeCore",
+        "PlatformComposeSceneTransitionLayout",
+        "androidx.compose.runtime_runtime",
+        "androidx.compose.material3_material3",
+        "androidx.compose.material_material-icons-extended",
+        "androidx.activity_activity-compose",
+        "androidx.compose.animation_animation-graphics",
     ],
     libs: [
         "keepanno-annotations",
@@ -230,6 +187,7 @@
         extra_check_modules: ["SystemUILintChecker"],
         warning_checks: ["MissingApacheLicenseDetector"],
     },
+    skip_jarjar_repackage: true,
 }
 
 filegroup {
@@ -336,15 +294,19 @@
         "ravenwood-junit",
         "platform-test-annotations",
         "notification_flags_lib",
+        "PlatformComposeCore",
+        "PlatformComposeSceneTransitionLayout",
+        "androidx.compose.runtime_runtime",
+        "androidx.compose.material3_material3",
+        "androidx.compose.material_material-icons-extended",
+        "androidx.activity_activity-compose",
+        "androidx.compose.animation_animation-graphics",
     ],
 }
 
 android_library {
     name: "SystemUI-tests",
     use_resource_processor: true,
-    defaults: [
-        "SystemUI_compose_defaults",
-    ],
     manifest: "tests/AndroidManifest-base.xml",
     additional_manifests: ["tests/AndroidManifest.xml"],
     srcs: [
@@ -356,6 +318,8 @@
         ":ReleaseJavaFiles",
         ":SystemUI-tests-multivalent",
         ":SystemUI-tests-utils",
+        "compose/features/src/**/*.kt",
+        "compose/facade/enabled/src/**/*.kt",
     ],
     static_libs: [
         "SystemUI-tests-base",
@@ -366,6 +330,7 @@
         "androidx.test.ext.truth",
         "kotlin-test",
         "SystemUICustomizationTestUtils",
+        "androidx.compose.runtime_runtime",
     ],
     libs: [
         "android.test.runner",
@@ -395,7 +360,6 @@
     defaults: [
         "platform_app_defaults",
         "SystemUI_optimized_defaults",
-        "SystemUI_compose_defaults",
     ],
     manifest: "tests/AndroidManifest-base.xml",
 
@@ -404,9 +368,12 @@
         "src/**/*.java",
         "src/**/I*.aidl",
         ":ReleaseJavaFiles",
+        "compose/features/src/**/*.kt",
+        "compose/facade/enabled/src/**/*.kt",
     ],
     static_libs: [
         "SystemUI-tests-base",
+        "androidx.compose.runtime_runtime",
     ],
     libs: [
         "keepanno-annotations",
@@ -550,5 +517,6 @@
     required: [
         "privapp_whitelist_com.android.systemui",
         "wmshell.protolog.json.gz",
+        "wmshell.protolog.pb",
     ],
 }
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
index 085fc29..88181e7 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
@@ -56,10 +56,12 @@
         implements View.OnTouchListener {
 
     public static final String PACKAGE_NAME = AccessibilityMenuService.class.getPackageName();
+    public static final String PACKAGE_TESTS = ".tests";
     public static final String INTENT_TOGGLE_MENU = ".toggle_menu";
     public static final String INTENT_HIDE_MENU = ".hide_menu";
     public static final String INTENT_GLOBAL_ACTION = ".global_action";
     public static final String INTENT_GLOBAL_ACTION_EXTRA = "GLOBAL_ACTION";
+    public static final String INTENT_OPEN_BLOCKED = "OPEN_BLOCKED";
 
     private static final String TAG = "A11yMenuService";
     private static final long BUFFER_MILLISECONDS_TO_PREVENT_UPDATE_FAILURE = 100L;
@@ -192,7 +194,7 @@
 
         IntentFilter hideMenuFilter = new IntentFilter();
         hideMenuFilter.addAction(Intent.ACTION_SCREEN_OFF);
-        hideMenuFilter.addAction(PACKAGE_NAME + INTENT_HIDE_MENU);
+        hideMenuFilter.addAction(INTENT_HIDE_MENU);
 
         // Including WRITE_SECURE_SETTINGS enforces that we only listen to apps
         // with the restricted WRITE_SECURE_SETTINGS permission who broadcast this intent.
@@ -200,7 +202,7 @@
                 Manifest.permission.WRITE_SECURE_SETTINGS, null,
                 Context.RECEIVER_EXPORTED);
         registerReceiver(mToggleMenuReceiver,
-                new IntentFilter(PACKAGE_NAME + INTENT_TOGGLE_MENU),
+                new IntentFilter(INTENT_TOGGLE_MENU),
                 Manifest.permission.WRITE_SECURE_SETTINGS, null,
                 Context.RECEIVER_EXPORTED);
 
@@ -245,8 +247,9 @@
      * @return {@code true} if successful, {@code false} otherwise.
      */
     private boolean performGlobalActionInternal(int globalAction) {
-        Intent intent = new Intent(PACKAGE_NAME + INTENT_GLOBAL_ACTION);
+        Intent intent = new Intent(INTENT_GLOBAL_ACTION);
         intent.putExtra(INTENT_GLOBAL_ACTION_EXTRA, globalAction);
+        intent.setPackage(PACKAGE_NAME + PACKAGE_TESTS);
         sendBroadcast(intent);
         Log.i("A11yMenuService", "Broadcasting global action " + globalAction);
         return performGlobalAction(globalAction);
@@ -410,9 +413,16 @@
 
     private void toggleVisibility() {
         boolean locked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
-        if (!locked && SystemClock.uptimeMillis() - mLastTimeTouchedOutside
-                        > BUTTON_CLICK_TIMEOUT) {
-            mA11yMenuLayout.toggleVisibility();
+        if (!locked) {
+            if (SystemClock.uptimeMillis() - mLastTimeTouchedOutside
+                    > BUTTON_CLICK_TIMEOUT) {
+                mA11yMenuLayout.toggleVisibility();
+            }
+        } else {
+            // Broadcast for testing.
+            Intent intent = new Intent(INTENT_OPEN_BLOCKED);
+            intent.setPackage(PACKAGE_NAME + PACKAGE_TESTS);
+            sendBroadcast(intent);
         }
     }
 }
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
index 72c1092..6546b87 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
@@ -23,6 +23,7 @@
 import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_RECENTS;
 import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT;
 
+import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_OPEN_BLOCKED;
 import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_GLOBAL_ACTION;
 import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_GLOBAL_ACTION_EXTRA;
 import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_HIDE_MENU;
@@ -65,6 +66,7 @@
 import org.junit.runner.RunWith;
 
 import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 @RunWith(AndroidJUnit4.class)
@@ -75,12 +77,11 @@
     private static final int TIMEOUT_SERVICE_STATUS_CHANGE_S = 5;
     private static final int TIMEOUT_UI_CHANGE_S = 5;
     private static final int NO_GLOBAL_ACTION = -1;
-    private static final String INPUT_KEYEVENT_KEYCODE_BACK = "input keyevent KEYCODE_BACK";
-    private static final String TEST_PIN = "1234";
 
     private static Instrumentation sInstrumentation;
     private static UiAutomation sUiAutomation;
-    private static AtomicInteger sLastGlobalAction;
+    private static final AtomicInteger sLastGlobalAction = new AtomicInteger(NO_GLOBAL_ACTION);
+    private static final AtomicBoolean sOpenBlocked = new AtomicBoolean(false);
 
     private static AccessibilityManager sAccessibilityManager;
     private static PowerManager sPowerManager;
@@ -122,8 +123,6 @@
                 () -> sAccessibilityManager.getEnabledAccessibilityServiceList(
                         AccessibilityServiceInfo.FEEDBACK_ALL_MASK).stream().filter(
                                 info -> info.getId().contains(serviceName)).count() == 1);
-
-        sLastGlobalAction = new AtomicInteger(NO_GLOBAL_ACTION);
         context.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
@@ -131,20 +130,28 @@
                 sLastGlobalAction.set(
                         intent.getIntExtra(INTENT_GLOBAL_ACTION_EXTRA, NO_GLOBAL_ACTION));
             }},
-                new IntentFilter(PACKAGE_NAME + INTENT_GLOBAL_ACTION),
+                new IntentFilter(INTENT_GLOBAL_ACTION),
+                null, null, Context.RECEIVER_EXPORTED);
+
+        context.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                Log.i(TAG, "Received notification that menu cannot be opened.");
+                sOpenBlocked.set(true);
+            }},
+                new IntentFilter(INTENT_OPEN_BLOCKED),
                 null, null, Context.RECEIVER_EXPORTED);
     }
 
     @AfterClass
-    public static void classTeardown() throws Throwable {
-        clearPin();
+    public static void classTeardown() {
         Settings.Secure.putString(sInstrumentation.getTargetContext().getContentResolver(),
                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "");
     }
 
     @Before
     public void setup() throws Throwable {
-        clearPin();
+        sOpenBlocked.set(false);
         wakeUpScreen();
         sUiAutomation.executeShellCommand("input keyevent KEYCODE_MENU");
         openMenu();
@@ -154,20 +161,8 @@
     public void tearDown() throws Throwable {
         closeMenu();
         sLastGlobalAction.set(NO_GLOBAL_ACTION);
-    }
-
-    private static void clearPin() throws Throwable {
-        sUiAutomation.executeShellCommand("locksettings clear --old " + TEST_PIN);
-        TestUtils.waitUntil("Device did not register as unlocked & insecure.",
-                TIMEOUT_SERVICE_STATUS_CHANGE_S,
-                () -> !sKeyguardManager.isDeviceSecure());
-    }
-
-    private static void setPin() throws Throwable {
-        sUiAutomation.executeShellCommand("locksettings set-pin " + TEST_PIN);
-        TestUtils.waitUntil("Device did not recognize as locked & secure.",
-                TIMEOUT_SERVICE_STATUS_CHANGE_S,
-                () -> sKeyguardManager.isDeviceSecure());
+        // dismisses screenshot popup if present.
+        sUiAutomation.executeShellCommand("input keyevent KEYCODE_BACK");
     }
 
     private static boolean isMenuVisible() {
@@ -184,7 +179,6 @@
 
     private static void closeScreen() throws Throwable {
         Display display = sDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
-        setPin();
         sUiAutomation.performGlobalAction(GLOBAL_ACTION_LOCK_SCREEN);
         TestUtils.waitUntil("Screen did not close.",
                 TIMEOUT_UI_CHANGE_S,
@@ -194,12 +188,20 @@
     }
 
     private static void openMenu() throws Throwable {
-        Intent intent = new Intent(PACKAGE_NAME + INTENT_TOGGLE_MENU);
+        openMenu(false);
+    }
+
+    private static void openMenu(boolean abandonOnBlock) throws Throwable {
+        Intent intent = new Intent(INTENT_TOGGLE_MENU);
+        intent.setPackage(PACKAGE_NAME);
         sInstrumentation.getContext().sendBroadcast(intent);
 
         TestUtils.waitUntil("Timed out before menu could appear.",
                 TIMEOUT_UI_CHANGE_S,
                 () -> {
+                    if (sOpenBlocked.get() && abandonOnBlock) {
+                        throw new IllegalStateException();
+                    }
                     if (isMenuVisible()) {
                         return true;
                     } else {
@@ -213,7 +215,8 @@
         if (!isMenuVisible()) {
             return;
         }
-        Intent intent = new Intent(PACKAGE_NAME + INTENT_HIDE_MENU);
+        Intent intent = new Intent(INTENT_HIDE_MENU);
+        intent.setPackage(PACKAGE_NAME);
         sInstrumentation.getContext().sendBroadcast(intent);
         TestUtils.waitUntil("Timed out before menu could close.",
                 TIMEOUT_UI_CHANGE_S, () -> !isMenuVisible());
@@ -444,13 +447,13 @@
         closeScreen();
         wakeUpScreen();
 
-        boolean timedOut = false;
+        boolean blocked = false;
         try {
-            openMenu();
-        } catch (AssertionError e) {
+            openMenu(true);
+        } catch (IllegalStateException e) {
             // Expected
-            timedOut = true;
+            blocked = true;
         }
-        assertThat(timedOut).isTrue();
+        assertThat(blocked).isTrue();
     }
 }
diff --git a/packages/SystemUI/aconfig/predictive_back.aconfig b/packages/SystemUI/aconfig/predictive_back.aconfig
index d0e6b28..7bbe82c 100644
--- a/packages/SystemUI/aconfig/predictive_back.aconfig
+++ b/packages/SystemUI/aconfig/predictive_back.aconfig
@@ -4,26 +4,26 @@
     name: "predictive_back_sysui"
     namespace: "systemui"
     description: "Predictive Back Dispatching for SysUI"
-    bug: "309545085"
+    bug: "327737297"
 }
 
 flag {
     name: "predictive_back_animate_shade"
     namespace: "systemui"
     description: "Enable Shade Animations"
-    bug: "309545085"
+    bug: "327732946"
 }
 
 flag {
     name: "predictive_back_animate_bouncer"
     namespace: "systemui"
     description: "Enable Predictive Back Animation in Bouncer"
-    bug: "309545085"
+    bug: "327733487"
 }
 
 flag {
     name: "predictive_back_animate_dialogs"
     namespace: "systemui"
     description: "Enable Predictive Back Animation for SysUI dialogs"
-    bug: "309545085"
+    bug: "327721544"
 }
\ No newline at end of file
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a69a2a6..8c8975f 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -76,6 +76,16 @@
 }
 
 flag {
+    name: "notification_content_alpha_optimization"
+    namespace: "systemui"
+    description: "Only reset alpha values of needed content views"
+    bug: "292024656"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "notifications_live_data_store_refactor"
     namespace: "systemui"
     description: "Replaces NotifLiveDataStore with ActiveNotificationListRepository, and updates consumers. "
@@ -84,6 +94,17 @@
 }
 
 flag {
+   name: "pss_app_selector_abrupt_exit_fix"
+   namespace: "systemui"
+   description: "Fixes the app selector abruptly disappearing without an animation, when the"
+        "selected task is the foreground task."
+   bug: "314385883"
+   metadata {
+        purpose: PURPOSE_BUGFIX
+   }
+}
+
+flag {
     name: "notifications_background_media_icons"
     namespace: "systemui"
     description: "Updates icons for media notifications in the background."
@@ -447,6 +468,13 @@
 }
 
 flag {
+    name: "hearing_aids_qs_tile_dialog"
+    namespace: "systemui"
+    description: "Show a dialog when clicking on hearing aids quick settings tile."
+    bug: "291423171"
+}
+
+flag {
     name: "notification_row_user_context"
     namespace: "systemui"
     description: "Create a user-specific Context for the ImageResolver in ExpandableNotificationRow"
@@ -546,3 +574,30 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "delayed_wakelock_release_on_background_thread"
+    namespace: "systemui"
+    description: "Released delayed wakelocks on background threads to avoid janking screen transitions."
+    bug: "316128516"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
+    name: "notify_power_manager_user_activity_background"
+    namespace: "systemui"
+    description: "Decide whether to notify the user activity to power manager in the background thread."
+    bug: "325203885"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
+    name: "media_controls_refactor"
+    namespace: "systemui"
+    description: "Refactors media code to follow the recommended architecture"
+    bug: "326408371"
+}
diff --git a/packages/SystemUI/animation/Android.bp b/packages/SystemUI/animation/Android.bp
index c1125f0..99b7c36 100644
--- a/packages/SystemUI/animation/Android.bp
+++ b/packages/SystemUI/animation/Android.bp
@@ -45,6 +45,7 @@
         "androidx.core_core-ktx",
         "androidx.annotation_annotation",
         "SystemUIShaderLib",
+        "WindowManager-Shell-shared",
         "animationlib",
     ],
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java
similarity index 98%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java
rename to packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java
index a78080f..e20425d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -11,10 +11,10 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
-package com.android.systemui.shared.system;
+package com.android.systemui.animation;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.view.WindowManager.TRANSIT_CLOSE;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationTargetCompat.java
similarity index 97%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
rename to packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationTargetCompat.java
index e4d9243..e251af4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationTargetCompat.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.system;
+package com.android.systemui.animation;
 
 import android.util.ArrayMap;
 import android.view.RemoteAnimationTarget;
diff --git a/packages/SystemUI/compose/core/TEST_MAPPING b/packages/SystemUI/compose/core/TEST_MAPPING
index ee95f73..b71c5fb 100644
--- a/packages/SystemUI/compose/core/TEST_MAPPING
+++ b/packages/SystemUI/compose/core/TEST_MAPPING
@@ -12,17 +12,6 @@
       ]
     },
     {
-      "name": "SystemUIComposeFeaturesTests",
-      "options": [
-        {
-          "exclude-annotation": "org.junit.Ignore"
-        },
-        {
-          "exclude-annotation": "androidx.test.filters.FlakyTest"
-        }
-      ]
-    },
-    {
       "name": "SystemUIComposeGalleryTests",
       "options": [
         {
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt b/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt
index 62dd4ac..ef15c84 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt
@@ -152,7 +152,10 @@
                         modifier =
                             Modifier.fillMaxHeight()
                                 .weight(1f)
-                                .padding(start = { paddingStart.roundToPx() }),
+                                .padding(
+                                    start = { paddingStart.roundToPx() },
+                                    end = { sliderHeight.roundToPx() / 2 },
+                                ),
                         contentAlignment = Alignment.CenterStart,
                     ) {
                         labelComposable(isDragging)
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
deleted file mode 100644
index 4398b25..0000000
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.systemui.compose
-
-import android.content.Context
-import android.view.View
-import android.view.WindowInsets
-import androidx.activity.ComponentActivity
-import androidx.lifecycle.LifecycleOwner
-import com.android.systemui.bouncer.ui.BouncerDialogFactory
-import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
-import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
-import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
-import com.android.systemui.communal.widgets.WidgetConfigurator
-import com.android.systemui.keyboard.stickykeys.ui.viewmodel.StickyKeysIndicatorViewModel
-import com.android.systemui.keyguard.shared.model.LockscreenSceneBlueprint
-import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
-import com.android.systemui.people.ui.viewmodel.PeopleViewModel
-import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
-import com.android.systemui.scene.shared.model.Scene
-import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
-import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.StateFlow
-
-/** The Compose facade, when Compose is *not* available. */
-object ComposeFacade : BaseComposeFacade {
-    override fun isComposeAvailable(): Boolean = false
-
-    override fun composeInitializer(): ComposeInitializer {
-        throwComposeUnavailableError()
-    }
-
-    override fun setPeopleSpaceActivityContent(
-        activity: ComponentActivity,
-        viewModel: PeopleViewModel,
-        onResult: (PeopleViewModel.Result) -> Unit,
-    ) {
-        throwComposeUnavailableError()
-    }
-
-    override fun setCommunalEditWidgetActivityContent(
-        activity: ComponentActivity,
-        viewModel: BaseCommunalViewModel,
-        widgetConfigurator: WidgetConfigurator,
-        onOpenWidgetPicker: () -> Unit,
-        onEditDone: () -> Unit,
-    ) {
-        throwComposeUnavailableError()
-    }
-
-    override fun setVolumePanelActivityContent(
-        activity: ComponentActivity,
-        viewModel: VolumePanelViewModel,
-        onDismiss: () -> Unit,
-    ) {
-        throwComposeUnavailableError()
-    }
-
-    override fun createFooterActionsView(
-        context: Context,
-        viewModel: FooterActionsViewModel,
-        qsVisibilityLifecycleOwner: LifecycleOwner
-    ): View {
-        throwComposeUnavailableError()
-    }
-
-    override fun createSceneContainerView(
-        scope: CoroutineScope,
-        context: Context,
-        viewModel: SceneContainerViewModel,
-        windowInsets: StateFlow<WindowInsets?>,
-        sceneByKey: Map<SceneKey, Scene>,
-        dataSourceDelegator: SceneDataSourceDelegator,
-    ): View {
-        throwComposeUnavailableError()
-    }
-
-    override fun createStickyKeysIndicatorContent(
-        context: Context,
-        viewModel: StickyKeysIndicatorViewModel
-    ): View {
-        throwComposeUnavailableError()
-    }
-
-    override fun createCommunalView(
-        context: Context,
-        viewModel: BaseCommunalViewModel,
-    ): View {
-        throwComposeUnavailableError()
-    }
-
-    override fun createCommunalContainer(context: Context, viewModel: CommunalViewModel): View {
-        throwComposeUnavailableError()
-    }
-
-    override fun createBouncer(
-        context: Context,
-        viewModel: BouncerViewModel,
-        dialogFactory: BouncerDialogFactory,
-    ): View = throwComposeUnavailableError()
-
-    override fun createLockscreen(
-        context: Context,
-        viewModel: LockscreenContentViewModel,
-        blueprints: Set<@JvmSuppressWildcards LockscreenSceneBlueprint>,
-    ): View = throwComposeUnavailableError()
-
-    private fun throwComposeUnavailableError(): Nothing {
-        error(
-            "Compose is not available. Make sure to check isComposeAvailable() before calling any" +
-                " other function on ComposeFacade."
-        )
-    }
-}
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/BouncerSceneModule.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/BouncerSceneModule.kt
deleted file mode 100644
index 1a5e22b..0000000
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/BouncerSceneModule.kt
+++ /dev/null
@@ -1,21 +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
-
-import dagger.Module
-
-@Module interface BouncerSceneModule
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/CommunalSceneModule.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/CommunalSceneModule.kt
deleted file mode 100644
index f80a906..0000000
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/CommunalSceneModule.kt
+++ /dev/null
@@ -1,21 +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
-
-import dagger.Module
-
-@Module interface CommunalSceneModule
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/LockscreenSceneModule.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
deleted file mode 100644
index fc3912e..0000000
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
+++ /dev/null
@@ -1,31 +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
-
-import com.android.systemui.keyguard.shared.model.LockscreenSceneBlueprint
-import dagger.Module
-import dagger.Provides
-
-@Module
-interface LockscreenSceneModule {
-    companion object {
-        @Provides
-        fun providesLockscreenBlueprints(): Set<LockscreenSceneBlueprint> {
-            return emptySet()
-        }
-    }
-}
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/QuickSettingsSceneModule.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/QuickSettingsSceneModule.kt
deleted file mode 100644
index 387b056..0000000
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/QuickSettingsSceneModule.kt
+++ /dev/null
@@ -1,21 +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
-
-import dagger.Module
-
-@Module interface QuickSettingsSceneModule
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ShadeSceneModule.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ShadeSceneModule.kt
deleted file mode 100644
index 232c421..0000000
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ShadeSceneModule.kt
+++ /dev/null
@@ -1,21 +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
-
-import dagger.Module
-
-@Module interface ShadeSceneModule
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/anc/AncModule.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/anc/AncModule.kt
deleted file mode 100644
index a4fb05d..0000000
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/anc/AncModule.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package com.android.systemui.volume.panel.component.anc
-
-import dagger.Module
-
-@Module interface AncModule
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/bottombar/BottomBarModule.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/bottombar/BottomBarModule.kt
deleted file mode 100644
index c8dae76..0000000
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/bottombar/BottomBarModule.kt
+++ /dev/null
@@ -1,21 +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.volume.panel.component.bottombar
-
-import dagger.Module
-
-@Module interface BottomBarModule
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/captioning/CaptioningModule.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/captioning/CaptioningModule.kt
deleted file mode 100644
index aeb5c5d..0000000
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/captioning/CaptioningModule.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.volume.panel.component.captioning
-
-import dagger.Module
-
-@Module interface CaptioningModule
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.kt
deleted file mode 100644
index b4cb098..0000000
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package com.android.systemui.volume.panel.component.volume
-
-import dagger.Module
-
-@Module interface VolumeSlidersModule
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
deleted file mode 100644
index 76931a2..0000000
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.compose
-
-import android.content.Context
-import android.graphics.Point
-import android.view.View
-import android.view.WindowInsets
-import androidx.activity.ComponentActivity
-import androidx.activity.compose.setContent
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.ComposeView
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
-import androidx.lifecycle.LifecycleOwner
-import com.android.compose.theme.LocalAndroidColorScheme
-import com.android.compose.theme.PlatformTheme
-import com.android.compose.ui.platform.DensityAwareComposeView
-import com.android.internal.policy.ScreenDecorationsUtils
-import com.android.systemui.bouncer.ui.BouncerDialogFactory
-import com.android.systemui.bouncer.ui.composable.BouncerContent
-import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
-import com.android.systemui.common.ui.compose.windowinsets.CutoutLocation
-import com.android.systemui.common.ui.compose.windowinsets.DisplayCutout
-import com.android.systemui.common.ui.compose.windowinsets.ScreenDecorProvider
-import com.android.systemui.communal.ui.compose.CommunalContainer
-import com.android.systemui.communal.ui.compose.CommunalHub
-import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
-import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
-import com.android.systemui.communal.widgets.WidgetConfigurator
-import com.android.systemui.keyboard.stickykeys.ui.view.createStickyKeyIndicatorView
-import com.android.systemui.keyboard.stickykeys.ui.viewmodel.StickyKeysIndicatorViewModel
-import com.android.systemui.keyguard.shared.model.LockscreenSceneBlueprint
-import com.android.systemui.keyguard.ui.composable.LockscreenContent
-import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint
-import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
-import com.android.systemui.people.ui.compose.PeopleScreen
-import com.android.systemui.people.ui.viewmodel.PeopleViewModel
-import com.android.systemui.qs.footer.ui.compose.FooterActions
-import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
-import com.android.systemui.scene.shared.model.Scene
-import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.ui.composable.ComposableScene
-import com.android.systemui.scene.ui.composable.SceneContainer
-import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
-import com.android.systemui.volume.panel.ui.composable.VolumePanelRoot
-import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
-
-/** The Compose facade, when Compose is available. */
-object ComposeFacade : BaseComposeFacade {
-    override fun isComposeAvailable(): Boolean = true
-
-    override fun composeInitializer(): ComposeInitializer = ComposeInitializerImpl
-
-    override fun setPeopleSpaceActivityContent(
-        activity: ComponentActivity,
-        viewModel: PeopleViewModel,
-        onResult: (PeopleViewModel.Result) -> Unit,
-    ) {
-        activity.setContent { PlatformTheme { PeopleScreen(viewModel, onResult) } }
-    }
-
-    override fun setCommunalEditWidgetActivityContent(
-        activity: ComponentActivity,
-        viewModel: BaseCommunalViewModel,
-        widgetConfigurator: WidgetConfigurator,
-        onOpenWidgetPicker: () -> Unit,
-        onEditDone: () -> Unit,
-    ) {
-        activity.setContent {
-            PlatformTheme {
-                Box(
-                    modifier =
-                        Modifier.fillMaxSize()
-                            .background(LocalAndroidColorScheme.current.outlineVariant),
-                ) {
-                    CommunalHub(
-                        viewModel = viewModel,
-                        onOpenWidgetPicker = onOpenWidgetPicker,
-                        widgetConfigurator = widgetConfigurator,
-                        onEditDone = onEditDone,
-                    )
-                }
-            }
-        }
-    }
-
-    override fun setVolumePanelActivityContent(
-        activity: ComponentActivity,
-        viewModel: VolumePanelViewModel,
-        onDismiss: () -> Unit,
-    ) {
-        activity.setContent {
-            VolumePanelRoot(
-                viewModel = viewModel,
-                onDismiss = onDismiss,
-            )
-        }
-    }
-
-    override fun createFooterActionsView(
-        context: Context,
-        viewModel: FooterActionsViewModel,
-        qsVisibilityLifecycleOwner: LifecycleOwner,
-    ): View {
-        return DensityAwareComposeView(context).apply {
-            setContent { PlatformTheme { FooterActions(viewModel, qsVisibilityLifecycleOwner) } }
-        }
-    }
-
-    override fun createSceneContainerView(
-        scope: CoroutineScope,
-        context: Context,
-        viewModel: SceneContainerViewModel,
-        windowInsets: StateFlow<WindowInsets?>,
-        sceneByKey: Map<SceneKey, Scene>,
-        dataSourceDelegator: SceneDataSourceDelegator,
-    ): View {
-        return ComposeView(context).apply {
-            setContent {
-                PlatformTheme {
-                    ScreenDecorProvider(
-                        displayCutout = displayCutoutFromWindowInsets(scope, context, windowInsets),
-                        screenCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
-                    ) {
-                        SceneContainer(
-                            viewModel = viewModel,
-                            sceneByKey =
-                                sceneByKey.mapValues { (_, scene) -> scene as ComposableScene },
-                            dataSourceDelegator = dataSourceDelegator,
-                        )
-                    }
-                }
-            }
-        }
-    }
-
-    override fun createStickyKeysIndicatorContent(
-        context: Context,
-        viewModel: StickyKeysIndicatorViewModel
-    ): View {
-        return createStickyKeyIndicatorView(context, viewModel)
-    }
-
-    override fun createCommunalView(
-        context: Context,
-        viewModel: BaseCommunalViewModel,
-    ): View {
-        return ComposeView(context).apply {
-            setContent { PlatformTheme { CommunalHub(viewModel = viewModel) } }
-        }
-    }
-
-    override fun createCommunalContainer(context: Context, viewModel: CommunalViewModel): View {
-        return ComposeView(context).apply {
-            setContent { PlatformTheme { CommunalContainer(viewModel = viewModel) } }
-        }
-    }
-
-    // TODO(b/298525212): remove once Compose exposes window inset bounds.
-    private fun displayCutoutFromWindowInsets(
-        scope: CoroutineScope,
-        context: Context,
-        windowInsets: StateFlow<WindowInsets?>,
-    ): StateFlow<DisplayCutout> =
-        windowInsets
-            .map {
-                val boundingRect = it?.displayCutout?.boundingRectTop
-                val width = boundingRect?.let { boundingRect.right - boundingRect.left } ?: 0
-                val left = boundingRect?.left?.toDp(context) ?: 0.dp
-                val top = boundingRect?.top?.toDp(context) ?: 0.dp
-                val right = boundingRect?.right?.toDp(context) ?: 0.dp
-                val bottom = boundingRect?.bottom?.toDp(context) ?: 0.dp
-                val location =
-                    when {
-                        width <= 0f -> CutoutLocation.NONE
-                        left <= 0.dp -> CutoutLocation.LEFT
-                        right >= getDisplayWidth(context) -> CutoutLocation.RIGHT
-                        else -> CutoutLocation.CENTER
-                    }
-                DisplayCutout(
-                    left,
-                    top,
-                    right,
-                    bottom,
-                    location,
-                )
-            }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), DisplayCutout())
-
-    // TODO(b/298525212): remove once Compose exposes window inset bounds.
-    private fun getDisplayWidth(context: Context): Dp {
-        val point = Point()
-        checkNotNull(context.display).getRealSize(point)
-        return point.x.dp
-    }
-
-    // TODO(b/298525212): remove once Compose exposes window inset bounds.
-    private fun Int.toDp(context: Context): Dp {
-        return (this.toFloat() / context.resources.displayMetrics.density).dp
-    }
-
-    override fun createBouncer(
-        context: Context,
-        viewModel: BouncerViewModel,
-        dialogFactory: BouncerDialogFactory,
-    ): View {
-        return ComposeView(context).apply {
-            setContent { PlatformTheme { BouncerContent(viewModel, dialogFactory) } }
-        }
-    }
-
-    override fun createLockscreen(
-        context: Context,
-        viewModel: LockscreenContentViewModel,
-        blueprints: Set<@JvmSuppressWildcards LockscreenSceneBlueprint>,
-    ): View {
-        val sceneBlueprints =
-            blueprints.mapNotNull { it as? ComposableLockscreenSceneBlueprint }.toSet()
-        return ComposeView(context).apply {
-            setContent {
-                LockscreenContent(viewModel = viewModel, blueprints = sceneBlueprints)
-                    .Content(modifier = Modifier.fillMaxSize())
-            }
-        }
-    }
-}
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeInitializerImpl.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeInitializerImpl.kt
deleted file mode 100644
index 1674591..0000000
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeInitializerImpl.kt
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.compose
-
-import android.view.View
-import androidx.lifecycle.findViewTreeLifecycleOwner
-import androidx.lifecycle.setViewTreeLifecycleOwner
-import androidx.lifecycle.Lifecycle
-import androidx.savedstate.SavedStateRegistryController
-import androidx.savedstate.SavedStateRegistryOwner
-import com.android.compose.animation.ViewTreeSavedStateRegistryOwner
-import com.android.systemui.lifecycle.ViewLifecycleOwner
-
-internal object ComposeInitializerImpl : ComposeInitializer {
-    override fun onAttachedToWindow(root: View) {
-        if (root.findViewTreeLifecycleOwner() != null) {
-            error("root $root already has a LifecycleOwner")
-        }
-
-        val parent = root.parent
-        if (parent is View && parent.id != android.R.id.content) {
-            error(
-                "ComposeInitializer.onAttachedToWindow(View) must be called on the content child." +
-                    "Outside of activities and dialogs, this is usually the top-most View of a " +
-                    "window."
-            )
-        }
-
-        // The lifecycle owner, which is STARTED when [root] is visible and RESUMED when [root] is
-        // both visible and focused.
-        val lifecycleOwner = ViewLifecycleOwner(root)
-
-        // We create a trivial implementation of [SavedStateRegistryOwner] that does not do any save
-        // or restore because SystemUI process is always running and top-level windows using this
-        // initializer are created once, when the process is started.
-        val savedStateRegistryOwner =
-            object : SavedStateRegistryOwner {
-                private val savedStateRegistryController =
-                    SavedStateRegistryController.create(this).apply { performRestore(null) }
-
-                override val savedStateRegistry = savedStateRegistryController.savedStateRegistry
-
-                override val lifecycle: Lifecycle
-                    get() = lifecycleOwner.lifecycle
-            }
-
-        // We must call [ViewLifecycleOwner.onCreate] after creating the [SavedStateRegistryOwner]
-        // because `onCreate` might move the lifecycle state to STARTED which will make
-        // [SavedStateRegistryController.performRestore] throw.
-        lifecycleOwner.onCreate()
-
-        // Set the owners on the root. They will be reused by any ComposeView inside the root
-        // hierarchy.
-        root.setViewTreeLifecycleOwner(lifecycleOwner)
-        ViewTreeSavedStateRegistryOwner.set(root, savedStateRegistryOwner)
-    }
-
-    override fun onDetachedFromWindow(root: View) {
-        (root.findViewTreeLifecycleOwner() as ViewLifecycleOwner).onDestroy()
-        root.setViewTreeLifecycleOwner(null)
-        ViewTreeSavedStateRegistryOwner.set(root, null)
-    }
-}
diff --git a/packages/SystemUI/compose/features/Android.bp b/packages/SystemUI/compose/features/Android.bp
deleted file mode 100644
index c12084d..0000000
--- a/packages/SystemUI/compose/features/Android.bp
+++ /dev/null
@@ -1,47 +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 {
-    default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
-    // 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: "SystemUIComposeFeatures",
-    use_resource_processor: true,
-    manifest: "AndroidManifest.xml",
-
-    srcs: [
-        "src/**/*.kt",
-    ],
-
-    static_libs: [
-        "SystemUI-core",
-        "PlatformComposeCore",
-        "PlatformComposeSceneTransitionLayout",
-
-        "androidx.compose.runtime_runtime",
-        "androidx.compose.animation_animation-graphics",
-        "androidx.compose.material3_material3",
-        "androidx.compose.material_material-icons-extended",
-        "androidx.activity_activity-compose",
-    ],
-
-    kotlincflags: ["-Xjvm-default=all"],
-}
diff --git a/packages/SystemUI/compose/features/AndroidManifest.xml b/packages/SystemUI/compose/features/AndroidManifest.xml
deleted file mode 100644
index c1a9ec5..0000000
--- a/packages/SystemUI/compose/features/AndroidManifest.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.systemui.compose.features">
-
-</manifest>
diff --git a/packages/SystemUI/compose/features/TEST_MAPPING b/packages/SystemUI/compose/features/TEST_MAPPING
deleted file mode 100644
index 7430acb..0000000
--- a/packages/SystemUI/compose/features/TEST_MAPPING
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "SystemUIComposeFeaturesTests",
-      "options": [
-        {
-          "exclude-annotation": "org.junit.Ignore"
-        },
-        {
-          "exclude-annotation": "androidx.test.filters.FlakyTest"
-        }
-      ]
-    },
-    {
-      "name": "SystemUIComposeGalleryTests",
-      "options": [
-        {
-          "exclude-annotation": "org.junit.Ignore"
-        },
-        {
-          "exclude-annotation": "androidx.test.filters.FlakyTest"
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
index 0469cbe..3ec5508 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
@@ -22,15 +22,17 @@
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import com.android.compose.animation.scene.Back
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.SwipeDirection
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
 import com.android.systemui.bouncer.ui.BouncerDialogFactory
 import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.scene.shared.model.Direction
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.shared.model.UserAction
-import com.android.systemui.scene.shared.model.UserActionResult
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.ui.composable.ComposableScene
 import javax.inject.Inject
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -52,13 +54,13 @@
     private val viewModel: BouncerViewModel,
     private val dialogFactory: BouncerDialogFactory,
 ) : ComposableScene {
-    override val key = SceneKey.Bouncer
+    override val key = Scenes.Bouncer
 
     override val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> =
         MutableStateFlow(
                 mapOf(
-                    UserAction.Back to UserActionResult(SceneKey.Lockscreen),
-                    UserAction.Swipe(Direction.DOWN) to UserActionResult(SceneKey.Lockscreen),
+                    Back to UserActionResult(Scenes.Lockscreen),
+                    Swipe(SwipeDirection.Down) to UserActionResult(Scenes.Lockscreen),
                 )
             )
             .asStateFlow()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index be5aa8a..9ee69bc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -9,12 +9,11 @@
 import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
+import androidx.compose.ui.res.dimensionResource
 import com.android.compose.animation.scene.Edge
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.FixedSizeEdgeDetector
 import com.android.compose.animation.scene.LowestZIndexScenePicker
-import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.compose.animation.scene.SceneKey
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.animation.scene.SceneTransitionLayout
@@ -24,13 +23,11 @@
 import com.android.compose.animation.scene.transitions
 import com.android.compose.animation.scene.updateSceneTransitionLayoutState
 import com.android.compose.theme.LocalAndroidColorScheme
-import com.android.systemui.communal.shared.model.CommunalSceneKey
-import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
+import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.communal.ui.compose.extensions.allowGestures
 import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
 import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.transform
+import com.android.systemui.res.R
 
 object Communal {
     object Elements {
@@ -40,7 +37,7 @@
 }
 
 val sceneTransitions = transitions {
-    to(TransitionSceneKey.Communal) {
+    to(CommunalScenes.Communal) {
         spec = tween(durationMillis = 1000)
         translate(Communal.Elements.Content, Edge.Right)
         timestampRange(startMillis = 167, endMillis = 334) {
@@ -48,7 +45,7 @@
             fade(Communal.Elements.Content)
         }
     }
-    to(TransitionSceneKey.Blank) {
+    to(CommunalScenes.Blank) {
         spec = tween(durationMillis = 1000)
         translate(Communal.Elements.Content, Edge.Right)
         timestampRange(endMillis = 167) { fade(Communal.Elements.Content) }
@@ -67,14 +64,11 @@
     modifier: Modifier = Modifier,
     viewModel: CommunalViewModel,
 ) {
-    val currentScene: SceneKey by
-        viewModel.currentScene
-            .transform { value -> emit(value.toTransitionSceneKey()) }
-            .collectAsState(TransitionSceneKey.Blank)
+    val currentScene: SceneKey by viewModel.currentScene.collectAsState(CommunalScenes.Blank)
     val sceneTransitionLayoutState =
         updateSceneTransitionLayoutState(
             currentScene,
-            onChangeScene = { viewModel.onSceneChanged(it.toCommunalSceneKey()) },
+            onChangeScene = { viewModel.onSceneChanged(it) },
             transitions = sceneTransitions,
         )
     val touchesAllowed by viewModel.touchesAllowed.collectAsState(initial = false)
@@ -82,23 +76,23 @@
     // This effect exposes the SceneTransitionLayout's observable transition state to the rest of
     // the system, and unsets it when the view is disposed to avoid a memory leak.
     DisposableEffect(viewModel, sceneTransitionLayoutState) {
-        viewModel.setTransitionState(
-            sceneTransitionLayoutState.observableTransitionState().map { it.toModel() }
-        )
+        viewModel.setTransitionState(sceneTransitionLayoutState.observableTransitionState())
         onDispose { viewModel.setTransitionState(null) }
     }
 
     SceneTransitionLayout(
         state = sceneTransitionLayoutState,
         modifier = modifier.fillMaxSize().allowGestures(allowed = touchesAllowed),
-        swipeSourceDetector = FixedSizeEdgeDetector(ContainerDimensions.EdgeSwipeSize),
+        swipeSourceDetector =
+            FixedSizeEdgeDetector(
+                dimensionResource(id = R.dimen.communal_gesture_initiation_width)
+            ),
     ) {
         scene(
-            TransitionSceneKey.Blank,
+            CommunalScenes.Blank,
             userActions =
                 mapOf(
-                    Swipe(SwipeDirection.Left, fromSource = Edge.Right) to
-                        TransitionSceneKey.Communal
+                    Swipe(SwipeDirection.Left, fromSource = Edge.Right) to CommunalScenes.Communal
                 )
         ) {
             // This scene shows nothing only allowing for transitions to the communal scene.
@@ -106,11 +100,9 @@
         }
 
         scene(
-            TransitionSceneKey.Communal,
+            CommunalScenes.Communal,
             userActions =
-                mapOf(
-                    Swipe(SwipeDirection.Right, fromSource = Edge.Left) to TransitionSceneKey.Blank
-                ),
+                mapOf(Swipe(SwipeDirection.Right, fromSource = Edge.Left) to CommunalScenes.Blank),
         ) {
             CommunalScene(viewModel, modifier = modifier)
         }
@@ -131,43 +123,3 @@
     )
     Box(modifier.element(Communal.Elements.Content)) { CommunalHub(viewModel = viewModel) }
 }
-
-// TODO(b/315490861): Remove these conversions once Compose can be used throughout SysUI.
-object TransitionSceneKey {
-    val Blank = CommunalSceneKey.Blank.toTransitionSceneKey()
-    val Communal = CommunalSceneKey.Communal.toTransitionSceneKey()
-}
-
-// TODO(b/315490861): Remove these conversions once Compose can be used throughout SysUI.
-fun SceneKey.toCommunalSceneKey(): CommunalSceneKey {
-    return this.identity as CommunalSceneKey
-}
-
-// TODO(b/315490861): Remove these conversions once Compose can be used throughout SysUI.
-fun CommunalSceneKey.toTransitionSceneKey(): SceneKey {
-    return SceneKey(debugName = toString(), identity = this)
-}
-
-/**
- * Converts between the [SceneTransitionLayout] state class and our forked data class that can be
- * used throughout SysUI.
- */
-// TODO(b/315490861): Remove these conversions once Compose can be used throughout SysUI.
-fun ObservableTransitionState.toModel(): ObservableCommunalTransitionState {
-    return when (this) {
-        is ObservableTransitionState.Idle ->
-            ObservableCommunalTransitionState.Idle(scene.toCommunalSceneKey())
-        is ObservableTransitionState.Transition ->
-            ObservableCommunalTransitionState.Transition(
-                fromScene = fromScene.toCommunalSceneKey(),
-                toScene = toScene.toCommunalSceneKey(),
-                progress = progress,
-                isInitiatedByUserInput = isInitiatedByUserInput,
-                isUserInputOngoing = isUserInputOngoing,
-            )
-    }
-}
-
-object ContainerDimensions {
-    val EdgeSwipeSize = 40.dp
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 622a4f0..515c816 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.communal.ui.compose
 
 import android.appwidget.AppWidgetHostView
+import android.graphics.drawable.Icon
 import android.os.Bundle
 import android.util.SizeF
 import android.widget.FrameLayout
@@ -26,11 +27,12 @@
 import androidx.compose.animation.fadeOut
 import androidx.compose.foundation.BorderStroke
 import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.Image
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ColumnScope
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Spacer
@@ -77,6 +79,8 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.ColorMatrix
 import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.input.pointer.pointerInput
 import androidx.compose.ui.layout.LayoutCoordinates
@@ -85,8 +89,11 @@
 import androidx.compose.ui.layout.onSizeChanged
 import androidx.compose.ui.layout.positionInWindow
 import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.semantics.testTagsAsResourceId
@@ -101,6 +108,8 @@
 import androidx.core.view.setPadding
 import com.android.compose.modifiers.thenIf
 import com.android.compose.theme.LocalAndroidColorScheme
+import com.android.compose.ui.graphics.painter.rememberDrawablePainter
+import com.android.internal.R.dimen.system_app_widget_background_radius
 import com.android.systemui.communal.domain.model.CommunalContentModel
 import com.android.systemui.communal.shared.model.CommunalContentSize
 import com.android.systemui.communal.ui.compose.Dimensions.CardOutlineWidth
@@ -110,6 +119,7 @@
 import com.android.systemui.communal.ui.compose.extensions.observeTapsWithoutConsuming
 import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
 import com.android.systemui.communal.ui.viewmodel.CommunalEditModeViewModel
+import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
 import com.android.systemui.communal.widgets.WidgetConfigurator
 import com.android.systemui.res.R
 import kotlinx.coroutines.launch
@@ -178,7 +188,7 @@
                             // not display this button.
                             if (
                                 index == null ||
-                                    communalContent[index].isWidget() ||
+                                    communalContent[index].isWidgetContent() ||
                                     communalContent[index] is CommunalContentModel.CtaTileInViewMode
                             ) {
                                 isButtonToEditWidgetsShowing = true
@@ -189,26 +199,37 @@
                     }
                 },
     ) {
-        CommunalHubLazyGrid(
-            communalContent = communalContent,
-            viewModel = viewModel,
-            contentPadding = contentPadding,
-            contentOffset = contentOffset,
-            setGridCoordinates = { gridCoordinates = it },
-            updateDragPositionForRemove = { offset ->
-                isDraggingToRemove =
-                    isPointerWithinCoordinates(
-                        offset = gridCoordinates?.let { it.positionInWindow() + offset },
-                        containerToCheck = removeButtonCoordinates
-                    )
-                isDraggingToRemove
-            },
-            onOpenWidgetPicker = onOpenWidgetPicker,
-            gridState = gridState,
-            contentListState = contentListState,
-            selectedKey = selectedKey,
-            widgetConfigurator = widgetConfigurator,
-        )
+        Column(Modifier.align(Alignment.TopStart)) {
+            CommunalHubLazyGrid(
+                communalContent = communalContent,
+                viewModel = viewModel,
+                contentPadding = contentPadding,
+                contentOffset = contentOffset,
+                setGridCoordinates = { gridCoordinates = it },
+                updateDragPositionForRemove = { offset ->
+                    isDraggingToRemove =
+                        isPointerWithinCoordinates(
+                            offset = gridCoordinates?.let { it.positionInWindow() + offset },
+                            containerToCheck = removeButtonCoordinates
+                        )
+                    isDraggingToRemove
+                },
+                onOpenWidgetPicker = onOpenWidgetPicker,
+                gridState = gridState,
+                contentListState = contentListState,
+                selectedKey = selectedKey,
+                widgetConfigurator = widgetConfigurator,
+            )
+            // TODO(b/326060686): Remove this once keyguard indication area can persist over hub
+            if (viewModel is CommunalViewModel) {
+                val isUnlocked by viewModel.deviceUnlocked.collectAsState(initial = false)
+                Spacer(Modifier.height(24.dp))
+                LockStateIcon(
+                    isUnlocked = isUnlocked,
+                    modifier = Modifier.align(Alignment.CenterHorizontally),
+                )
+            }
+        }
 
         if (viewModel.isEditMode && onOpenWidgetPicker != null && onEditDone != null) {
             Toolbar(
@@ -260,7 +281,7 @@
 
 @OptIn(ExperimentalFoundationApi::class)
 @Composable
-private fun BoxScope.CommunalHubLazyGrid(
+private fun ColumnScope.CommunalHubLazyGrid(
     communalContent: List<CommunalContentModel>,
     viewModel: BaseCommunalViewModel,
     contentPadding: PaddingValues,
@@ -274,7 +295,7 @@
     widgetConfigurator: WidgetConfigurator?,
 ) {
     var gridModifier =
-        Modifier.align(Alignment.CenterStart).onGloballyPositioned { setGridCoordinates(it) }
+        Modifier.align(Alignment.Start).onGloballyPositioned { setGridCoordinates(it) }
     var list = communalContent
     var dragDropState: GridDragDropState? = null
     if (viewModel.isEditMode && viewModel is CommunalEditModeViewModel) {
@@ -309,8 +330,8 @@
         state = gridState,
         rows = GridCells.Fixed(CommunalContentSize.FULL.span),
         contentPadding = contentPadding,
-        horizontalArrangement = Arrangement.spacedBy(Dimensions.Spacing),
-        verticalArrangement = Arrangement.spacedBy(Dimensions.Spacing),
+        horizontalArrangement = Arrangement.spacedBy(32.dp),
+        verticalArrangement = Arrangement.spacedBy(32.dp),
     ) {
         items(
             count = list.size,
@@ -330,7 +351,7 @@
                 DraggableItem(
                     dragDropState = dragDropState,
                     selected = selected,
-                    enabled = list[index] is CommunalContentModel.Widget,
+                    enabled = list[index].isWidgetContent(),
                     index = index,
                 ) { isDragging ->
                     CommunalContent(
@@ -356,6 +377,26 @@
     }
 }
 
+@Composable
+private fun LockStateIcon(
+    isUnlocked: Boolean,
+    modifier: Modifier = Modifier,
+) {
+    val colors = LocalAndroidColorScheme.current
+    val resource =
+        if (isUnlocked) {
+            R.drawable.ic_unlocked
+        } else {
+            R.drawable.ic_lock
+        }
+    Icon(
+        painter = painterResource(id = resource),
+        contentDescription = null,
+        tint = colors.onPrimaryContainer,
+        modifier = modifier.size(52.dp)
+    )
+}
+
 /**
  * Toolbar that contains action buttons to
  * 1) open the widget picker
@@ -539,9 +580,11 @@
     widgetConfigurator: WidgetConfigurator? = null,
 ) {
     when (model) {
-        is CommunalContentModel.Widget ->
+        is CommunalContentModel.WidgetContent.Widget ->
             WidgetContent(viewModel, model, size, selected, widgetConfigurator, modifier)
         is CommunalContentModel.WidgetPlaceholder -> HighlightedItem(modifier)
+        is CommunalContentModel.WidgetContent.DisabledWidget ->
+            DisabledWidgetPlaceholder(model, modifier)
         is CommunalContentModel.CtaTileInViewMode -> CtaTileInViewModeContent(viewModel, modifier)
         is CommunalContentModel.CtaTileInEditMode ->
             CtaTileInEditModeContent(modifier, onOpenWidgetPicker)
@@ -672,7 +715,7 @@
 @Composable
 private fun WidgetContent(
     viewModel: BaseCommunalViewModel,
-    model: CommunalContentModel.Widget,
+    model: CommunalContentModel.WidgetContent.Widget,
     size: SizeF,
     selected: Boolean,
     widgetConfigurator: WidgetConfigurator?,
@@ -681,19 +724,21 @@
     Box(
         modifier = modifier,
     ) {
-        val paddingInPx = with(LocalDensity.current) { CardOutlineWidth.toPx().toInt() }
+        val paddingInPx =
+            if (selected) with(LocalDensity.current) { CardOutlineWidth.toPx().toInt() } else 0
         AndroidView(
             modifier = Modifier.fillMaxSize().allowGestures(allowed = !viewModel.isEditMode),
             factory = { context ->
-                val view =
-                    model.appWidgetHost
-                        .createViewForCommunal(context, model.appWidgetId, model.providerInfo)
-                        .apply { updateAppWidgetSize(Bundle.EMPTY, listOf(size)) }
+                model.appWidgetHost
+                    .createViewForCommunal(context, model.appWidgetId, model.providerInfo)
+                    .apply { updateAppWidgetSize(Bundle.EMPTY, listOf(size)) }
+            },
+            update = { view ->
                 // Remove the extra padding applied to AppWidgetHostView to allow widgets to
-                // occupy the entire box. The added padding is now adjusted to leave only sufficient
-                // space for displaying the outline around the box when the widget is selected.
+                // occupy the entire box. The added padding is now adjusted to leave only
+                // sufficient space for displaying the outline around the box when the widget
+                // is selected.
                 view.setPadding(paddingInPx)
-                view
             },
             // For reusing composition in lazy lists.
             onReset = {},
@@ -716,7 +761,7 @@
 @Composable
 fun WidgetConfigureButton(
     visible: Boolean,
-    model: CommunalContentModel.Widget,
+    model: CommunalContentModel.WidgetContent.Widget,
     modifier: Modifier = Modifier,
     widgetConfigurator: WidgetConfigurator,
 ) {
@@ -751,6 +796,38 @@
 }
 
 @Composable
+fun DisabledWidgetPlaceholder(
+    model: CommunalContentModel.WidgetContent.DisabledWidget,
+    modifier: Modifier = Modifier,
+) {
+    val context = LocalContext.current
+    val appInfo = model.appInfo
+    val icon: Icon =
+        if (appInfo == null || appInfo.icon == 0) {
+            Icon.createWithResource(context, android.R.drawable.sym_def_app_icon)
+        } else {
+            Icon.createWithResource(appInfo.packageName, appInfo.icon)
+        }
+
+    Column(
+        modifier =
+            modifier.background(
+                MaterialTheme.colorScheme.surfaceVariant,
+                RoundedCornerShape(dimensionResource(system_app_widget_background_radius))
+            ),
+        verticalArrangement = Arrangement.Center,
+        horizontalAlignment = Alignment.CenterHorizontally,
+    ) {
+        Image(
+            painter = rememberDrawablePainter(icon.loadDrawable(context)),
+            contentDescription = stringResource(R.string.icon_description_for_disabled_widget),
+            modifier = Modifier.size(48.dp),
+            colorFilter = ColorFilter.colorMatrix(Colors.DisabledColorFilter),
+        )
+    }
+}
+
+@Composable
 private fun SmartspaceContent(
     model: CommunalContentModel.Smartspace,
     modifier: Modifier = Modifier,
@@ -795,7 +872,7 @@
 @Composable
 private fun gridContentPadding(isEditMode: Boolean, toolbarSize: IntSize?): PaddingValues {
     if (!isEditMode || toolbarSize == null) {
-        return PaddingValues(horizontal = Dimensions.Spacing)
+        return PaddingValues(start = 48.dp, end = 48.dp, top = Dimensions.GridTopSpacing)
     }
     val configuration = LocalConfiguration.current
     val density = LocalDensity.current
@@ -851,19 +928,20 @@
 
 /** Returns the key of item if it's editable at the given index. Only widget is editable. */
 private fun keyAtIndexIfEditable(list: List<CommunalContentModel>, index: Int): String? =
-    if (index in list.indices && list[index].isWidget()) list[index].key else null
+    if (index in list.indices && list[index].isWidgetContent()) list[index].key else null
 
 data class ContentPaddingInPx(val start: Float, val top: Float) {
     fun toOffset(): Offset = Offset(start, top)
 }
 
 object Dimensions {
-    val CardWidth = 464.dp
-    val CardHeightFull = 630.dp
-    val CardHeightHalf = 307.dp
-    val CardHeightThird = 199.dp
+    val CardWidth = 424.dp
+    val CardHeightFull = 596.dp
+    val CardHeightHalf = 282.dp
+    val CardHeightThird = 177.33.dp
     val CardOutlineWidth = 3.dp
-    val GridHeight = CardHeightFull
+    val GridTopSpacing = 72.dp
+    val GridHeight = CardHeightFull + GridTopSpacing
     val Spacing = 16.dp
 
     // The sizing/padding of the toolbar in glanceable hub edit mode
@@ -880,5 +958,30 @@
     val IconSize = 48.dp
 }
 
+private object Colors {
+    val DisabledColorFilter by lazy { disabledColorMatrix() }
+
+    /** Returns the disabled image filter. Ported over from [DisableImageView]. */
+    private fun disabledColorMatrix(): ColorMatrix {
+        val brightnessMatrix = ColorMatrix()
+        val brightnessAmount = 0.5f
+        val brightnessRgb = (255 * brightnessAmount).toInt().toFloat()
+        // Brightness: C-new = C-old*(1-amount) + amount
+        val scale = 1f - brightnessAmount
+        val mat = brightnessMatrix.values
+        mat[0] = scale
+        mat[6] = scale
+        mat[12] = scale
+        mat[4] = brightnessRgb
+        mat[9] = brightnessRgb
+        mat[14] = brightnessRgb
+
+        return ColorMatrix().apply {
+            setToSaturation(0F)
+            timesAssign(brightnessMatrix)
+        }
+    }
+}
+
 /** The resource id of communal hub accessible from UiAutomator. */
 private const val COMMUNAL_HUB_TEST_TAG = "communal_hub"
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt
index 11a38f9..3d88ad5 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt
@@ -19,12 +19,13 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.SwipeDirection
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
 import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.scene.shared.model.Direction
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.shared.model.UserAction
-import com.android.systemui.scene.shared.model.UserActionResult
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.ui.composable.ComposableScene
 import javax.inject.Inject
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -38,12 +39,12 @@
 constructor(
     private val viewModel: CommunalViewModel,
 ) : ComposableScene {
-    override val key = SceneKey.Communal
+    override val key = Scenes.Communal
 
     override val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> =
         MutableStateFlow<Map<UserAction, UserActionResult>>(
                 mapOf(
-                    UserAction.Swipe(Direction.RIGHT) to UserActionResult(SceneKey.Lockscreen),
+                    Swipe(SwipeDirection.Right) to UserActionResult(Scenes.Lockscreen),
                 )
             )
             .asStateFlow()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt
index 9b8c9d0..c5dab33 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt
@@ -71,8 +71,8 @@
 
     /** Remove widget from the list and the database. */
     fun onRemove(indexToRemove: Int) {
-        if (list[indexToRemove] is CommunalContentModel.Widget) {
-            val widget = list[indexToRemove] as CommunalContentModel.Widget
+        if (list[indexToRemove].isWidgetContent()) {
+            val widget = list[indexToRemove] as CommunalContentModel.WidgetContent
             list.apply { removeAt(indexToRemove) }
             onDeleteWidget(widget.appWidgetId)
         }
@@ -100,7 +100,7 @@
         val widgetIdToPriorityMap: Map<Int, Int> =
             list
                 .mapIndexedNotNull { index, item ->
-                    if (item is CommunalContentModel.Widget) {
+                    if (item is CommunalContentModel.WidgetContent) {
                         item.appWidgetId to list.size - index
                     } else {
                         null
@@ -115,5 +115,5 @@
     }
 
     /** Returns true if the item at given index is editable. */
-    fun isItemEditable(index: Int) = list[index] is CommunalContentModel.Widget
+    fun isItemEditable(index: Int) = list[index].isWidgetContent()
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt
index dd86646..a8d801a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt
@@ -18,8 +18,11 @@
 
 import android.content.Context
 import android.view.View
+import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.heightIn
 import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
 import androidx.compose.material3.LocalContentColor
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Surface
@@ -61,22 +64,32 @@
 @Composable
 fun StickyKeysIndicator(stickyKeys: Map<ModifierKey, Locked>, modifier: Modifier = Modifier) {
     Surface(
-        color = MaterialTheme.colorScheme.surface,
+        color = MaterialTheme.colorScheme.inverseSurface,
         shape = MaterialTheme.shapes.medium,
-        modifier = modifier
+        modifier = modifier.heightIn(min = 84.dp).width(96.dp)
     ) {
         Column(
             horizontalAlignment = Alignment.CenterHorizontally,
+            verticalArrangement = Arrangement.Center,
             modifier = Modifier.padding(16.dp)
         ) {
-            stickyKeys.forEach { (key, isLocked) ->
-                key(key) {
-                    Text(
-                        text = key.displayedText,
-                        fontWeight = if (isLocked.locked) FontWeight.Bold else FontWeight.Normal
-                    )
-                }
-            }
+            stickyKeys.forEach { (key, isLocked) -> key(key) { StickyKeyText(key, isLocked) } }
         }
     }
 }
+
+@Composable
+private fun StickyKeyText(key: ModifierKey, isLocked: Locked, modifier: Modifier = Modifier) {
+    Text(
+        text = key.displayedText,
+        fontWeight = if (isLocked.locked) FontWeight.Bold else FontWeight.Normal,
+        style = MaterialTheme.typography.bodyMedium,
+        color =
+            if (isLocked.locked) {
+                MaterialTheme.colorScheme.inverseOnSurface
+            } else {
+                MaterialTheme.colorScheme.outlineVariant
+            },
+        modifier = modifier
+    )
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
index dd043db..a02781b 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
@@ -18,19 +18,20 @@
 
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
+import com.android.compose.animation.scene.Edge
+import com.android.compose.animation.scene.SceneKey
 import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.SwipeDirection
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
 import com.android.compose.animation.scene.animateSceneFloatAsState
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel
 import com.android.systemui.qs.ui.composable.QuickSettings
-import com.android.systemui.scene.shared.model.Direction
-import com.android.systemui.scene.shared.model.Edge
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.shared.model.UserAction
-import com.android.systemui.scene.shared.model.UserActionResult
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.ui.composable.ComposableScene
 import dagger.Lazy
 import javax.inject.Inject
@@ -50,7 +51,7 @@
     viewModel: LockscreenSceneViewModel,
     private val lockscreenContent: Lazy<LockscreenContent>,
 ) : ComposableScene {
-    override val key = SceneKey.Lockscreen
+    override val key = Scenes.Lockscreen
 
     override val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> =
         combine(viewModel.upDestinationSceneKey, viewModel.leftDestinationSceneKey, ::Pair)
@@ -80,11 +81,11 @@
         left: SceneKey?,
     ): Map<UserAction, UserActionResult> {
         return buildMap {
-            up?.let { this[UserAction.Swipe(Direction.UP)] = UserActionResult(up) }
-            left?.let { this[UserAction.Swipe(Direction.LEFT)] = UserActionResult(left) }
-            this[UserAction.Swipe(fromEdge = Edge.TOP, direction = Direction.DOWN)] =
-                UserActionResult(SceneKey.QuickSettings)
-            this[UserAction.Swipe(direction = Direction.DOWN)] = UserActionResult(SceneKey.Shade)
+            up?.let { this[Swipe(SwipeDirection.Up)] = UserActionResult(up) }
+            left?.let { this[Swipe(SwipeDirection.Left)] = UserActionResult(left) }
+            this[Swipe(fromSource = Edge.Top, direction = SwipeDirection.Down)] =
+                UserActionResult(Scenes.QuickSettings)
+            this[Swipe(direction = SwipeDirection.Down)] = UserActionResult(Scenes.Shade)
         }
     }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
index 452dc03..d23cd0c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
@@ -35,11 +35,13 @@
 import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
 import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection
 import com.android.systemui.keyguard.ui.composable.section.LockSection
+import com.android.systemui.keyguard.ui.composable.section.MediaCarouselSection
 import com.android.systemui.keyguard.ui.composable.section.NotificationSection
 import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
 import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
 import com.android.systemui.keyguard.ui.composable.section.StatusBarSection
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
+import com.android.systemui.media.controls.ui.composable.MediaCarousel
 import com.android.systemui.res.R
 import dagger.Binds
 import dagger.Module
@@ -63,6 +65,7 @@
     private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>,
     private val bottomAreaSection: BottomAreaSection,
     private val settingsMenuSection: SettingsMenuSection,
+    private val mediaCarouselSection: MediaCarouselSection,
     private val clockInteractor: KeyguardClockInteractor,
 ) : ComposableLockscreenSceneBlueprint {
 
@@ -112,10 +115,16 @@
 
                         if (viewModel.isLargeClockVisible) {
                             Spacer(modifier = Modifier.weight(weight = 1f))
-                            with(clockSection) { LargeClock(modifier = Modifier.fillMaxWidth()) }
+                            with(clockSection) {
+                                LargeClock(
+                                    modifier = Modifier.fillMaxWidth(),
+                                )
+                            }
                         }
 
-                        if (viewModel.areNotificationsVisible) {
+                        with(mediaCarouselSection) { MediaCarousel() }
+
+                        if (viewModel.areNotificationsVisible(resources = resources)) {
                             with(notificationSection) {
                                 Notifications(
                                     modifier = Modifier.fillMaxWidth().weight(weight = 1f)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
index 71c60c7..c422c4b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
@@ -35,6 +35,7 @@
 import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
 import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection
 import com.android.systemui.keyguard.ui.composable.section.LockSection
+import com.android.systemui.keyguard.ui.composable.section.MediaCarouselSection
 import com.android.systemui.keyguard.ui.composable.section.NotificationSection
 import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
 import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
@@ -63,6 +64,7 @@
     private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>,
     private val bottomAreaSection: BottomAreaSection,
     private val settingsMenuSection: SettingsMenuSection,
+    private val mediaCarouselSection: MediaCarouselSection,
     private val clockInteractor: KeyguardClockInteractor,
 ) : ComposableLockscreenSceneBlueprint {
 
@@ -115,7 +117,9 @@
                             with(clockSection) { LargeClock(modifier = Modifier.fillMaxWidth()) }
                         }
 
-                        if (viewModel.areNotificationsVisible) {
+                        with(mediaCarouselSection) { MediaCarousel() }
+
+                        if (viewModel.areNotificationsVisible(resources = resources)) {
                             with(notificationSection) {
                                 Notifications(
                                     modifier = Modifier.fillMaxWidth().weight(weight = 1f)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt
index af836b6..d218425 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt
@@ -41,6 +41,7 @@
 import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
 import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection
 import com.android.systemui.keyguard.ui.composable.section.LockSection
+import com.android.systemui.keyguard.ui.composable.section.MediaCarouselSection
 import com.android.systemui.keyguard.ui.composable.section.NotificationSection
 import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
 import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
@@ -70,6 +71,7 @@
     private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>,
     private val bottomAreaSection: BottomAreaSection,
     private val settingsMenuSection: SettingsMenuSection,
+    private val mediaCarouselSection: MediaCarouselSection,
     private val clockInteractor: KeyguardClockInteractor,
     private val largeScreenHeaderHelper: LargeScreenHeaderHelper,
 ) : ComposableLockscreenSceneBlueprint {
@@ -100,6 +102,14 @@
                                 modifier = Modifier.fillMaxHeight().weight(weight = 1f),
                                 horizontalAlignment = Alignment.CenterHorizontally,
                             ) {
+                                with(clockSection) {
+                                    SmallClock(
+                                        burnInParams = burnIn.parameters,
+                                        onTopChanged = burnIn.onSmallClockTopChanged,
+                                        modifier = Modifier.fillMaxWidth(),
+                                    )
+                                }
+
                                 with(smartSpaceSection) {
                                     SmartSpace(
                                         burnInParams = burnIn.parameters,
@@ -121,9 +131,13 @@
                                     )
                                 }
 
-                                Spacer(modifier = Modifier.weight(weight = 1f))
-                                with(clockSection) { LargeClock() }
-                                Spacer(modifier = Modifier.weight(weight = 1f))
+                                if (viewModel.isLargeClockVisible) {
+                                    Spacer(modifier = Modifier.weight(weight = 1f))
+                                    with(clockSection) { LargeClock() }
+                                    Spacer(modifier = Modifier.weight(weight = 1f))
+                                }
+
+                                with(mediaCarouselSection) { MediaCarousel() }
                             }
                             with(notificationSection) {
                                 val splitShadeTopMargin: Dp =
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt
index e2e7a95..f86623f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt
@@ -41,12 +41,14 @@
 import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection
 import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
 import com.android.systemui.keyguard.ui.composable.section.LockSection
+import com.android.systemui.keyguard.ui.composable.section.MediaCarouselSection
 import com.android.systemui.keyguard.ui.composable.section.NotificationSection
 import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
 import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
 import com.android.systemui.keyguard.ui.composable.section.StatusBarSection
 import com.android.systemui.keyguard.ui.composable.section.WeatherClockSection
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
+import com.android.systemui.media.controls.ui.composable.MediaCarousel
 import com.android.systemui.res.R
 import com.android.systemui.shade.LargeScreenHeaderHelper
 import dagger.Binds
@@ -68,6 +70,7 @@
     private val bottomAreaSection: BottomAreaSection,
     private val settingsMenuSection: SettingsMenuSection,
     private val clockInteractor: KeyguardClockInteractor,
+    private val mediaCarouselSection: MediaCarouselSection,
 ) : ComposableLockscreenSceneBlueprint {
 
     override val id: String = WEATHER_CLOCK_BLUEPRINT_ID
@@ -107,7 +110,9 @@
                             )
                         }
 
-                        if (viewModel.areNotificationsVisible) {
+                        with(mediaCarouselSection) { MediaCarousel() }
+
+                        if (viewModel.areNotificationsVisible(resources = resources)) {
                             with(notificationSection) {
                                 Notifications(
                                     modifier = Modifier.fillMaxWidth().weight(weight = 1f)
@@ -228,6 +233,7 @@
     private val clockInteractor: KeyguardClockInteractor,
     private val largeScreenHeaderHelper: LargeScreenHeaderHelper,
     private val weatherClockSection: WeatherClockSection,
+    private val mediaCarouselSection: MediaCarouselSection,
 ) : ComposableLockscreenSceneBlueprint {
     override val id: String = SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
 
@@ -276,6 +282,8 @@
                                                 ),
                                     )
                                 }
+
+                                with(mediaCarouselSection) { MediaCarousel() }
                             }
                             with(notificationSection) {
                                 val splitShadeTopMargin: Dp =
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
index 335c915..152cc67 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
@@ -39,7 +39,6 @@
 import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
 import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
-import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
 import javax.inject.Inject
 
 /** Provides small clock and large clock composables for the default clock face. */
@@ -49,7 +48,6 @@
     private val viewModel: KeyguardClockViewModel,
     private val clockInteractor: KeyguardClockInteractor,
     private val aodBurnInViewModel: AodBurnInViewModel,
-    private val lockscreenSmartspaceController: LockscreenSmartspaceController,
 ) {
 
     @Composable
@@ -62,15 +60,11 @@
         val currentClock by viewModel.currentClock.collectAsState()
         viewModel.clock = currentClock
 
-        if (clockSize != KeyguardClockSwitch.SMALL) {
+        if (clockSize != KeyguardClockSwitch.SMALL || currentClock?.smallClock?.view == null) {
             onTopChanged(null)
             return
         }
 
-        if (currentClock?.smallClock?.view == null) {
-            return
-        }
-
         val view = LocalView.current
 
         DisposableEffect(view) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
index 4c76fb4..31d3fa0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.util.DisplayMetrics
+import android.view.View
 import android.view.WindowManager
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
@@ -37,6 +38,7 @@
 import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.flags.FeatureFlagsClassic
 import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.ui.binder.DeviceEntryIconViewBinder
 import com.android.systemui.keyguard.ui.composable.blueprint.BlueprintAlignmentLines
 import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
 import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryBackgroundViewModel
@@ -44,6 +46,7 @@
 import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.res.R
+import com.android.systemui.shade.NotificationPanelView
 import com.android.systemui.statusbar.VibratorHelper
 import dagger.Lazy
 import javax.inject.Inject
@@ -62,6 +65,7 @@
     private val deviceEntryBackgroundViewModel: Lazy<DeviceEntryBackgroundViewModel>,
     private val falsingManager: Lazy<FalsingManager>,
     private val vibratorHelper: Lazy<VibratorHelper>,
+    private val notificationPanelView: NotificationPanelView,
 ) {
     @Composable
     fun SceneScope.LockIcon(modifier: Modifier = Modifier) {
@@ -69,6 +73,10 @@
             return
         }
 
+        notificationPanelView.findViewById<View?>(R.id.lock_icon_view)?.let {
+            notificationPanelView.removeView(it)
+        }
+
         val context = LocalContext.current
 
         AndroidView(
@@ -77,16 +85,15 @@
                     if (DeviceEntryUdfpsRefactor.isEnabled) {
                         DeviceEntryIconView(context, null).apply {
                             id = R.id.device_entry_icon_view
-                            // TODO: b/326624996 Bind the DeviceEntryIcon
-                            //                            DeviceEntryIconViewBinder.bind(
-                            //                                applicationScope,
-                            //                                this,
-                            //                                deviceEntryIconViewModel.get(),
-                            //                                deviceEntryForegroundViewModel.get(),
-                            //                                deviceEntryBackgroundViewModel.get(),
-                            //                                falsingManager.get(),
-                            //                                vibratorHelper.get(),
-                            //                            )
+                            DeviceEntryIconViewBinder.bind(
+                                applicationScope,
+                                this,
+                                deviceEntryIconViewModel.get(),
+                                deviceEntryForegroundViewModel.get(),
+                                deviceEntryBackgroundViewModel.get(),
+                                falsingManager.get(),
+                                vibratorHelper.get(),
+                            )
                         }
                     } else {
                         // keyguardBottomAreaRefactor()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
new file mode 100644
index 0000000..dae120c
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.composable.section
+
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.onSizeChanged
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.res.dimensionResource
+import com.android.compose.animation.scene.SceneScope
+import com.android.systemui.keyguard.ui.viewmodel.MediaCarouselViewModel
+import com.android.systemui.media.controls.ui.composable.MediaCarousel
+import com.android.systemui.media.controls.ui.controller.MediaCarouselController
+import com.android.systemui.media.controls.ui.view.MediaHost
+import com.android.systemui.media.dagger.MediaModule
+import com.android.systemui.res.R
+import com.android.systemui.util.animation.MeasurementInput
+import javax.inject.Inject
+import javax.inject.Named
+
+class MediaCarouselSection
+@Inject
+constructor(
+    private val mediaCarouselController: MediaCarouselController,
+    @param:Named(MediaModule.KEYGUARD) private val mediaHost: MediaHost,
+    private val mediaCarouselViewModel: MediaCarouselViewModel,
+) {
+
+    @Composable
+    fun SceneScope.MediaCarousel(modifier: Modifier = Modifier) {
+        if (!mediaCarouselViewModel.isMediaVisible) {
+            return
+        }
+
+        if (mediaCarouselController.mediaFrame == null) {
+            return
+        }
+
+        val mediaHeight = dimensionResource(R.dimen.qs_media_session_height_expanded)
+        // TODO(b/312714128): MediaPlayer background size is not as expected.
+        MediaCarousel(
+            modifier =
+                modifier.height(mediaHeight).fillMaxWidth().onSizeChanged { size ->
+                    // Notify controller to size the carousel for the
+                    // current space
+                    mediaHost.measurementInput = MeasurementInput(size.width, size.height)
+                    mediaCarouselController.setSceneContainerSize(size.width, size.height)
+                },
+            mediaHost = mediaHost,
+            layoutWidth = 0, // Layout width is not used.
+            layoutHeight = with(LocalDensity.current) { mediaHeight.toPx() }.toInt(),
+            carouselController = mediaCarouselController,
+        )
+    }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
index 61b2d4e..d3e4553 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
@@ -16,9 +16,12 @@
 
 package com.android.systemui.media.controls.ui.composable
 
+import android.view.ViewGroup
+import android.widget.FrameLayout
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.viewinterop.AndroidView
+import androidx.core.view.contains
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.SceneScope
 import com.android.systemui.media.controls.ui.controller.MediaCarouselController
@@ -45,6 +48,20 @@
 
     AndroidView(
         modifier = modifier.element(MediaCarousel.Elements.Content),
-        factory = { _ -> carouselController.mediaFrame },
+        factory = { context ->
+            FrameLayout(context).apply {
+                val mediaFrame = carouselController.mediaFrame
+                (mediaFrame.parent as? ViewGroup)?.removeView(mediaFrame)
+                addView(mediaFrame)
+            }
+        },
+        update = {
+            if (it.contains(carouselController.mediaFrame)) {
+                return@AndroidView
+            }
+            val mediaFrame = carouselController.mediaFrame
+            (mediaFrame.parent as? ViewGroup)?.removeView(mediaFrame)
+            it.addView(mediaFrame)
+        },
     )
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
index ef6ae2e..791d629 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
@@ -71,8 +71,7 @@
 import com.android.systemui.notifications.ui.composable.Notifications.Form
 import com.android.systemui.notifications.ui.composable.Notifications.TransitionThresholds.EXPANSION_FOR_MAX_CORNER_RADIUS
 import com.android.systemui.notifications.ui.composable.Notifications.TransitionThresholds.EXPANSION_FOR_MAX_SCRIM_ALPHA
-import com.android.systemui.scene.ui.composable.Gone
-import com.android.systemui.scene.ui.composable.Shade
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.ui.composable.ShadeHeader
 import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationStackAppearanceViewBinder.SCRIM_CORNER_RADIUS
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
@@ -214,7 +213,7 @@
                     // in step with the transition so that it is 0 when it completes.
                     if (
                         scrimOffset.value < 0 &&
-                            layoutState.isTransitioning(from = Shade, to = Gone)
+                            layoutState.isTransitioning(from = Scenes.Shade, to = Scenes.Gone)
                     ) {
                         IntOffset(x = 0, y = (scrimOffset.value * expansionFraction).roundToInt())
                     } else {
@@ -226,7 +225,7 @@
                         calculateCornerRadius(
                                 screenCornerRadius,
                                 { expansionFraction },
-                                layoutState.isTransitioningBetween(Gone, Shade)
+                                layoutState.isTransitioningBetween(Scenes.Gone, Scenes.Shade)
                             )
                             .let {
                                 RoundedCornerShape(
@@ -250,7 +249,7 @@
                 Modifier.fillMaxSize()
                     .graphicsLayer {
                         alpha =
-                            if (layoutState.isTransitioningBetween(Gone, Shade)) {
+                            if (layoutState.isTransitioningBetween(Scenes.Gone, Scenes.Shade)) {
                                 (expansionFraction / EXPANSION_FOR_MAX_SCRIM_ALPHA).coerceAtMost(1f)
                             } else 1f
                     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
index 5d0b9ba..91b737d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
@@ -37,14 +37,13 @@
 import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Companion.Collapsing
 import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Expanding
 import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Unsquishing
-import com.android.systemui.scene.ui.composable.QuickSettings as QuickSettingsSceneKey
-import com.android.systemui.scene.ui.composable.Shade
+import com.android.systemui.scene.shared.model.Scenes
 
 object QuickSettings {
     private val SCENES =
         setOf(
-            QuickSettingsSceneKey,
-            Shade,
+            Scenes.QuickSettings,
+            Scenes.Shade,
         )
 
     object Elements {
@@ -69,18 +68,20 @@
     return when (val transitionState = layoutState.transitionState) {
         is TransitionState.Idle -> {
             when (transitionState.currentScene) {
-                Shade -> QSSceneAdapter.State.QQS
-                QuickSettingsSceneKey -> QSSceneAdapter.State.QS
+                Scenes.Shade -> QSSceneAdapter.State.QQS
+                Scenes.QuickSettings -> QSSceneAdapter.State.QS
                 else -> QSSceneAdapter.State.CLOSED
             }
         }
         is TransitionState.Transition ->
             with(transitionState) {
                 when {
-                    fromScene == Shade && toScene == QuickSettingsSceneKey -> Expanding(progress)
-                    fromScene == QuickSettingsSceneKey && toScene == Shade -> Collapsing(progress)
-                    fromScene == Shade || toScene == Shade -> Unsquishing(squishiness)
-                    fromScene == QuickSettingsSceneKey || toScene == QuickSettingsSceneKey -> {
+                    fromScene == Scenes.Shade && toScene == Scenes.QuickSettings ->
+                        Expanding(progress)
+                    fromScene == Scenes.QuickSettings && toScene == Scenes.Shade ->
+                        Collapsing(progress)
+                    fromScene == Scenes.Shade || toScene == Scenes.Shade -> Unsquishing(squishiness)
+                    fromScene == Scenes.QuickSettings || toScene == Scenes.QuickSettings -> {
                         QSSceneAdapter.State.QS
                     }
                     else ->
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 66cef86..3b8b863 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
@@ -40,7 +40,6 @@
 import androidx.compose.foundation.layout.wrapContentHeight
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.verticalScroll
-import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
@@ -51,6 +50,7 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.compose.ui.res.colorResource
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.animation.scene.TransitionState
@@ -62,9 +62,9 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.qs.footer.ui.compose.FooterActions
 import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.res.R
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.ui.composable.ComposableScene
-import com.android.systemui.scene.ui.composable.asComposeAware
 import com.android.systemui.shade.ui.composable.CollapsedShadeHeader
 import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
 import com.android.systemui.shade.ui.composable.Shade
@@ -88,7 +88,7 @@
     private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
     private val statusBarIconController: StatusBarIconController,
 ) : ComposableScene {
-    override val key = SceneKey.QuickSettings
+    override val key = Scenes.QuickSettings
 
     override val destinationScenes =
         viewModel.destinationScenes.stateIn(
@@ -139,9 +139,7 @@
         val isScrollable =
             when (val state = layoutState.transitionState) {
                 is TransitionState.Idle -> true
-                is TransitionState.Transition -> {
-                    state.fromScene == SceneKey.QuickSettings.asComposeAware()
-                }
+                is TransitionState.Transition -> state.fromScene == Scenes.QuickSettings
             }
 
         LaunchedEffect(isCustomizing, scrollState) {
@@ -168,7 +166,7 @@
             modifier =
                 Modifier.element(Shade.Elements.BackgroundScrim)
                     .fillMaxSize()
-                    .background(MaterialTheme.colorScheme.scrim)
+                    .background(colorResource(R.color.shade_scrim_background_dark))
         )
         Column(
             horizontalAlignment = Alignment.CenterHorizontally,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposeAwareExtensions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposeAwareExtensions.kt
deleted file mode 100644
index a7de1ee..0000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposeAwareExtensions.kt
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.scene.ui.composable
-
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.IntSize
-import com.android.compose.animation.scene.Back
-import com.android.compose.animation.scene.Edge as ComposeAwareEdge
-import com.android.compose.animation.scene.SceneKey as ComposeAwareSceneKey
-import com.android.compose.animation.scene.Swipe
-import com.android.compose.animation.scene.SwipeDirection
-import com.android.compose.animation.scene.TransitionKey as ComposeAwareTransitionKey
-import com.android.compose.animation.scene.UserAction as ComposeAwareUserAction
-import com.android.compose.animation.scene.UserActionDistance as ComposeAwareUserActionDistance
-import com.android.compose.animation.scene.UserActionResult as ComposeAwareUserActionResult
-import com.android.systemui.scene.shared.model.Direction
-import com.android.systemui.scene.shared.model.Edge
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.shared.model.TransitionKey
-import com.android.systemui.scene.shared.model.UserAction
-import com.android.systemui.scene.shared.model.UserActionDistance
-import com.android.systemui.scene.shared.model.UserActionResult
-
-// TODO(b/293899074): remove this file once we can use the types from SceneTransitionLayout.
-
-fun SceneKey.asComposeAware(): ComposeAwareSceneKey {
-    return ComposeAwareSceneKey(
-        debugName = toString(),
-        identity = this,
-    )
-}
-
-fun TransitionKey.asComposeAware(): ComposeAwareTransitionKey {
-    return ComposeAwareTransitionKey(
-        debugName = debugName,
-        identity = this,
-    )
-}
-
-fun UserAction.asComposeAware(): ComposeAwareUserAction {
-    return when (this) {
-        is UserAction.Swipe ->
-            Swipe(
-                pointerCount = pointerCount,
-                fromSource =
-                    when (this.fromEdge) {
-                        null -> null
-                        Edge.LEFT -> ComposeAwareEdge.Left
-                        Edge.TOP -> ComposeAwareEdge.Top
-                        Edge.RIGHT -> ComposeAwareEdge.Right
-                        Edge.BOTTOM -> ComposeAwareEdge.Bottom
-                    },
-                direction =
-                    when (this.direction) {
-                        Direction.LEFT -> SwipeDirection.Left
-                        Direction.UP -> SwipeDirection.Up
-                        Direction.RIGHT -> SwipeDirection.Right
-                        Direction.DOWN -> SwipeDirection.Down
-                    }
-            )
-        is UserAction.Back -> Back
-    }
-}
-
-fun UserActionResult.asComposeAware(): ComposeAwareUserActionResult {
-    val composeUnaware = this
-    return ComposeAwareUserActionResult(
-        toScene = composeUnaware.toScene.asComposeAware(),
-        transitionKey = composeUnaware.transitionKey?.asComposeAware(),
-        distance = composeUnaware.distance?.asComposeAware(),
-    )
-}
-
-fun UserActionDistance.asComposeAware(): ComposeAwareUserActionDistance {
-    val composeUnware = this
-    return object : ComposeAwareUserActionDistance {
-        override fun Density.absoluteDistance(
-            fromSceneSize: IntSize,
-            orientation: Orientation,
-        ): Float {
-            return composeUnware.absoluteDistance(
-                fromSceneWidth = fromSceneSize.width,
-                fromSceneHeight = fromSceneSize.height,
-                isHorizontal = orientation == Orientation.Horizontal,
-            )
-        }
-    }
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposeUnawareExtensions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposeUnawareExtensions.kt
deleted file mode 100644
index 4c03664..0000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposeUnawareExtensions.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.scene.ui.composable
-
-import com.android.compose.animation.scene.ObservableTransitionState as ComposeAwareObservableTransitionState
-import com.android.compose.animation.scene.SceneKey as ComposeAwareSceneKey
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
-
-fun ComposeAwareSceneKey.asComposeUnaware(): SceneKey {
-    return this.identity as SceneKey
-}
-
-fun ComposeAwareObservableTransitionState.asComposeUnaware(): ObservableTransitionState {
-    return when (this) {
-        is ComposeAwareObservableTransitionState.Idle ->
-            ObservableTransitionState.Idle(scene.asComposeUnaware())
-        is ComposeAwareObservableTransitionState.Transition ->
-            ObservableTransitionState.Transition(
-                fromScene = fromScene.asComposeUnaware(),
-                toScene = toScene.asComposeUnaware(),
-                progress = progress,
-                isInitiatedByUserInput = isInitiatedByUserInput,
-                isUserInputOngoing = isUserInputOngoing,
-            )
-    }
-}
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 9ca751e..82f56ab 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
@@ -19,17 +19,17 @@
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
+import com.android.compose.animation.scene.Edge
 import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.SwipeDirection
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
 import com.android.compose.animation.scene.animateSceneFloatAsState
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.qs.ui.composable.QuickSettings
-import com.android.systemui.scene.shared.model.Direction
-import com.android.systemui.scene.shared.model.Edge
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.shared.model.UserAction
-import com.android.systemui.scene.shared.model.UserActionResult
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
 import javax.inject.Inject
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -46,18 +46,17 @@
 constructor(
     private val notificationsViewModel: NotificationsPlaceholderViewModel,
 ) : ComposableScene {
-    override val key = SceneKey.Gone
+    override val key = Scenes.Gone
 
     override val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> =
         MutableStateFlow<Map<UserAction, UserActionResult>>(
                 mapOf(
-                    UserAction.Swipe(
+                    Swipe(
                         pointerCount = 2,
-                        fromEdge = Edge.TOP,
-                        direction = Direction.DOWN,
-                    ) to UserActionResult(SceneKey.QuickSettings),
-                    UserAction.Swipe(direction = Direction.DOWN) to
-                        UserActionResult(SceneKey.Shade),
+                        fromSource = Edge.Top,
+                        direction = SwipeDirection.Down,
+                    ) to UserActionResult(Scenes.QuickSettings),
+                    Swipe(direction = SwipeDirection.Down) to UserActionResult(Scenes.Shade),
                 )
             )
             .asStateFlow()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index 9779d71..0fdaabe 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -35,15 +35,14 @@
 import androidx.compose.ui.input.pointer.motionEventSpy
 import androidx.compose.ui.input.pointer.pointerInput
 import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
+import com.android.compose.animation.scene.SceneKey
 import com.android.compose.animation.scene.SceneTransitionLayout
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
 import com.android.compose.animation.scene.observableTransitionState
 import com.android.systemui.ribbon.ui.composable.BottomRightCornerRibbon
 import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.shared.model.UserAction
-import com.android.systemui.scene.shared.model.UserActionResult
 import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
-import kotlinx.coroutines.flow.map
 
 /**
  * Renders a container of a collection of "scenes" that the user can switch between using certain
@@ -77,8 +76,8 @@
         currentScene.destinationScenes.collectAsState()
     val state: MutableSceneTransitionLayoutState = remember {
         MutableSceneTransitionLayoutState(
-            initialScene = currentSceneKey.asComposeAware(),
-            canChangeScene = { toScene -> viewModel.canChangeScene(toScene.asComposeUnaware()) },
+            initialScene = currentSceneKey,
+            canChangeScene = { toScene -> viewModel.canChangeScene(toScene) },
             transitions = SceneContainerTransitions,
         )
     }
@@ -90,9 +89,7 @@
     }
 
     DisposableEffect(viewModel, state) {
-        viewModel.setTransitionState(
-            state.observableTransitionState().map { it.asComposeUnaware() }
-        )
+        viewModel.setTransitionState(state.observableTransitionState())
         onDispose { viewModel.setTransitionState(null) }
     }
 
@@ -116,23 +113,17 @@
         ) {
             sceneByKey.forEach { (sceneKey, composableScene) ->
                 scene(
-                    key = sceneKey.asComposeAware(),
+                    key = sceneKey,
                     userActions =
                         if (sceneKey == currentSceneKey) {
-                                currentDestinations
-                            } else {
-                                composableScene.destinationScenes.value
-                            }
-                            .map { (userAction, userActionResult) ->
-                                userAction.asComposeAware() to userActionResult.asComposeAware()
-                            }
-                            .toMap(),
+                            currentDestinations
+                        } else {
+                            composableScene.destinationScenes.value
+                        },
                 ) {
                     with(composableScene) {
                         this@scene.Content(
-                            modifier =
-                                Modifier.element(sceneKey.asComposeAware().rootElementKey)
-                                    .fillMaxSize(),
+                            modifier = Modifier.element(sceneKey.rootElementKey).fillMaxSize(),
                         )
                     }
                 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
index 61f8120..dea9485 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
@@ -1,6 +1,7 @@
 package com.android.systemui.scene.ui.composable
 
 import com.android.compose.animation.scene.transitions
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.shared.model.TransitionKeys.CollapseShadeInstantly
 import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse
 import com.android.systemui.scene.ui.composable.transitions.bouncerToGoneTransition
@@ -26,41 +27,41 @@
  * Please keep the list sorted alphabetically.
  */
 val SceneContainerTransitions = transitions {
-    from(Bouncer, to = Gone) { bouncerToGoneTransition() }
-    from(Gone, to = Shade) { goneToShadeTransition() }
+    from(Scenes.Bouncer, to = Scenes.Gone) { bouncerToGoneTransition() }
+    from(Scenes.Gone, to = Scenes.Shade) { goneToShadeTransition() }
     from(
-        Gone,
-        to = Shade,
-        key = CollapseShadeInstantly.asComposeAware(),
+        Scenes.Gone,
+        to = Scenes.Shade,
+        key = CollapseShadeInstantly,
     ) {
         goneToShadeTransition(durationScale = 0.0)
     }
     from(
-        Gone,
-        to = Shade,
-        key = SlightlyFasterShadeCollapse.asComposeAware(),
+        Scenes.Gone,
+        to = Scenes.Shade,
+        key = SlightlyFasterShadeCollapse,
     ) {
         goneToShadeTransition(durationScale = 0.9)
     }
-    from(Gone, to = QuickSettings) { goneToQuickSettingsTransition() }
-    from(Lockscreen, to = Bouncer) { lockscreenToBouncerTransition() }
-    from(Lockscreen, to = Communal) { lockscreenToCommunalTransition() }
-    from(Lockscreen, to = Shade) { lockscreenToShadeTransition() }
+    from(Scenes.Gone, to = Scenes.QuickSettings) { goneToQuickSettingsTransition() }
+    from(Scenes.Lockscreen, to = Scenes.Bouncer) { lockscreenToBouncerTransition() }
+    from(Scenes.Lockscreen, to = Scenes.Communal) { lockscreenToCommunalTransition() }
+    from(Scenes.Lockscreen, to = Scenes.Shade) { lockscreenToShadeTransition() }
     from(
-        Lockscreen,
-        to = Shade,
-        key = CollapseShadeInstantly.asComposeAware(),
+        Scenes.Lockscreen,
+        to = Scenes.Shade,
+        key = CollapseShadeInstantly,
     ) {
         lockscreenToShadeTransition(durationScale = 0.0)
     }
     from(
-        Lockscreen,
-        to = Shade,
-        key = SlightlyFasterShadeCollapse.asComposeAware(),
+        Scenes.Lockscreen,
+        to = Scenes.Shade,
+        key = SlightlyFasterShadeCollapse,
     ) {
         lockscreenToShadeTransition(durationScale = 0.9)
     }
-    from(Lockscreen, to = QuickSettings) { lockscreenToQuickSettingsTransition() }
-    from(Lockscreen, to = Gone) { lockscreenToGoneTransition() }
-    from(Shade, to = QuickSettings) { shadeToQuickSettingsTransition() }
+    from(Scenes.Lockscreen, to = Scenes.QuickSettings) { lockscreenToQuickSettingsTransition() }
+    from(Scenes.Lockscreen, to = Scenes.Gone) { lockscreenToGoneTransition() }
+    from(Scenes.Shade, to = Scenes.QuickSettings) { shadeToQuickSettingsTransition() }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt
index 60c0b77..a54994d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt
@@ -20,10 +20,10 @@
 
 import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
 import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.TransitionKey
 import com.android.compose.animation.scene.observableTransitionState
 import com.android.systemui.scene.shared.model.SceneDataSource
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.shared.model.TransitionKey
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.SharingStarted
@@ -61,11 +61,10 @@
                         }
                 }
             }
-            .map { it.asComposeUnaware() }
             .stateIn(
                 scope = coroutineScope,
                 started = SharingStarted.WhileSubscribed(),
-                initialValue = state.transitionState.currentScene.asComposeUnaware(),
+                initialValue = state.transitionState.currentScene,
             )
 
     override fun changeScene(
@@ -73,8 +72,8 @@
         transitionKey: TransitionKey?,
     ) {
         state.setTargetScene(
-            targetScene = toScene.asComposeAware(),
-            transitionKey = transitionKey?.asComposeAware(),
+            targetScene = toScene,
+            transitionKey = transitionKey,
             coroutineScope = coroutineScope,
         )
     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/TransitionSceneKeys.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/TransitionSceneKeys.kt
deleted file mode 100644
index 5a9add1..0000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/TransitionSceneKeys.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.android.systemui.scene.ui.composable
-
-import com.android.systemui.scene.shared.model.SceneKey
-
-val Lockscreen = SceneKey.Lockscreen.asComposeAware()
-val Bouncer = SceneKey.Bouncer.asComposeAware()
-val Shade = SceneKey.Shade.asComposeAware()
-val QuickSettings = SceneKey.QuickSettings.asComposeAware()
-val Gone = SceneKey.Gone.asComposeAware()
-val Communal = SceneKey.Communal.asComposeAware()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromBouncerToGoneTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromBouncerToGoneTransition.kt
index 1a9face..5eefe49 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromBouncerToGoneTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromBouncerToGoneTransition.kt
@@ -2,10 +2,10 @@
 
 import androidx.compose.animation.core.tween
 import com.android.compose.animation.scene.TransitionBuilder
-import com.android.systemui.scene.ui.composable.Bouncer
+import com.android.systemui.scene.shared.model.Scenes
 
 fun TransitionBuilder.bouncerToGoneTransition() {
     spec = tween(durationMillis = 500)
 
-    fade(Bouncer.rootElementKey)
+    fade(Scenes.Bouncer.rootElementKey)
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsTransition.kt
index 291617f..5bd1583 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsTransition.kt
@@ -3,10 +3,10 @@
 import androidx.compose.animation.core.tween
 import com.android.compose.animation.scene.Edge
 import com.android.compose.animation.scene.TransitionBuilder
-import com.android.systemui.scene.ui.composable.QuickSettings
+import com.android.systemui.scene.shared.model.Scenes
 
 fun TransitionBuilder.goneToQuickSettingsTransition() {
     spec = tween(durationMillis = 500)
 
-    translate(QuickSettings.rootElementKey, Edge.Top, true)
+    translate(Scenes.QuickSettings.rootElementKey, Edge.Top, true)
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToCommunalTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToCommunalTransition.kt
index ea8110a..0021bf5 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToCommunalTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToCommunalTransition.kt
@@ -19,15 +19,14 @@
 import androidx.compose.animation.core.tween
 import com.android.compose.animation.scene.Edge
 import com.android.compose.animation.scene.TransitionBuilder
-import com.android.systemui.scene.ui.composable.Communal
-import com.android.systemui.scene.ui.composable.Lockscreen
+import com.android.systemui.scene.shared.model.Scenes
 
 fun TransitionBuilder.lockscreenToCommunalTransition() {
     spec = tween(durationMillis = 500)
 
     // Translate lockscreen to the left.
-    translate(Lockscreen.rootElementKey, Edge.Left)
+    translate(Scenes.Lockscreen.rootElementKey, Edge.Left)
 
     // Translate communal from the right.
-    translate(Communal.rootElementKey, Edge.Right)
+    translate(Scenes.Communal.rootElementKey, Edge.Right)
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToGoneTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToGoneTransition.kt
index da6306d..3e576bc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToGoneTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToGoneTransition.kt
@@ -2,10 +2,10 @@
 
 import androidx.compose.animation.core.tween
 import com.android.compose.animation.scene.TransitionBuilder
-import com.android.systemui.scene.ui.composable.Lockscreen
+import com.android.systemui.scene.shared.model.Scenes
 
 fun TransitionBuilder.lockscreenToGoneTransition() {
     spec = tween(durationMillis = 500)
 
-    fade(Lockscreen.rootElementKey)
+    fade(Scenes.Lockscreen.rootElementKey)
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsTransition.kt
index e63bc4e..962d822 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsTransition.kt
@@ -3,10 +3,10 @@
 import androidx.compose.animation.core.tween
 import com.android.compose.animation.scene.Edge
 import com.android.compose.animation.scene.TransitionBuilder
-import com.android.systemui.scene.ui.composable.QuickSettings
+import com.android.systemui.scene.shared.model.Scenes
 
 fun TransitionBuilder.lockscreenToQuickSettingsTransition() {
     spec = tween(durationMillis = 500)
 
-    translate(QuickSettings.rootElementKey, Edge.Top, true)
+    translate(Scenes.QuickSettings.rootElementKey, Edge.Top, true)
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
index d7911ea..12b07a3 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
@@ -63,8 +63,7 @@
 import com.android.systemui.common.ui.compose.windowinsets.LocalDisplayCutout
 import com.android.systemui.privacy.OngoingPrivacyChip
 import com.android.systemui.res.R
-import com.android.systemui.scene.ui.composable.QuickSettings
-import com.android.systemui.scene.ui.composable.Shade as ShadeKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.ui.composable.ShadeHeader.Dimensions.CollapsedHeight
 import com.android.systemui.shade.ui.composable.ShadeHeader.Values.ClockScale
 import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
@@ -443,7 +442,7 @@
         },
         update = { iconContainer ->
             iconContainer.setQsExpansionTransitioning(
-                layoutState.isTransitioningBetween(ShadeKey, QuickSettings)
+                layoutState.isTransitioningBetween(Scenes.Shade, Scenes.QuickSettings)
             )
             if (isSingleCarrier || !useExpandedFormat) {
                 iconContainer.removeIgnoredSlots(carrierIconSlots)
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 2e0ce42..3620cc5 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
@@ -26,7 +26,6 @@
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
@@ -37,11 +36,17 @@
 import androidx.compose.ui.layout.Layout
 import androidx.compose.ui.layout.layout
 import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.res.colorResource
 import androidx.compose.ui.res.dimensionResource
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.LowestZIndexScenePicker
+import com.android.compose.animation.scene.SceneKey
 import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.SwipeDirection
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
 import com.android.compose.animation.scene.animateSceneFloatAsState
 import com.android.compose.modifiers.thenIf
 import com.android.systemui.battery.BatteryMeterViewController
@@ -56,10 +61,7 @@
 import com.android.systemui.notifications.ui.composable.NotificationScrollingStack
 import com.android.systemui.qs.ui.composable.QuickSettings
 import com.android.systemui.res.R
-import com.android.systemui.scene.shared.model.Direction
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.shared.model.UserAction
-import com.android.systemui.scene.shared.model.UserActionResult
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.ui.composable.ComposableScene
 import com.android.systemui.shade.ui.viewmodel.ShadeSceneViewModel
 import com.android.systemui.statusbar.phone.StatusBarIconController
@@ -109,7 +111,7 @@
     private val mediaCarouselController: MediaCarouselController,
     @Named(QUICK_QS_PANEL) private val mediaHost: MediaHost,
 ) : ComposableScene {
-    override val key = SceneKey.Shade
+    override val key = Scenes.Shade
 
     override val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> =
         viewModel.upDestinationSceneKey
@@ -144,8 +146,8 @@
         up: SceneKey,
     ): Map<UserAction, UserActionResult> {
         return mapOf(
-            UserAction.Swipe(Direction.UP) to UserActionResult(up),
-            UserAction.Swipe(Direction.DOWN) to UserActionResult(SceneKey.QuickSettings),
+            Swipe(SwipeDirection.Up) to UserActionResult(up),
+            Swipe(SwipeDirection.Down) to UserActionResult(Scenes.QuickSettings),
         )
     }
 }
@@ -171,7 +173,7 @@
         modifier =
             modifier
                 .element(Shade.Elements.BackgroundScrim)
-                .background(MaterialTheme.colorScheme.scrim),
+                .background(colorResource(R.color.shade_scrim_background_dark)),
     )
     Box {
         Layout(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/bottombar/ui/BottomBarComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/bottombar/ui/BottomBarComponent.kt
index d401261..c08eb94 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/bottombar/ui/BottomBarComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/bottombar/ui/BottomBarComponent.kt
@@ -19,17 +19,17 @@
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.heightIn
+import androidx.compose.material3.Button
 import androidx.compose.material3.ButtonDefaults
 import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
-import com.android.compose.PlatformButton
-import com.android.compose.PlatformOutlinedButton
 import com.android.systemui.res.R
 import com.android.systemui.volume.panel.component.bottombar.ui.viewmodel.BottomBarViewModel
 import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
@@ -47,11 +47,11 @@
     @Composable
     override fun VolumePanelComposeScope.Content(modifier: Modifier) {
         Row(
-            modifier = modifier.height(if (isLargeScreen) 54.dp else 48.dp).fillMaxWidth(),
+            modifier = modifier.heightIn(min = if (isLargeScreen) 54.dp else 48.dp).fillMaxWidth(),
             horizontalArrangement = Arrangement.SpaceBetween,
             verticalAlignment = Alignment.CenterVertically,
         ) {
-            PlatformOutlinedButton(
+            OutlinedButton(
                 onClick = viewModel::onSettingsClicked,
                 colors =
                     ButtonDefaults.outlinedButtonColors(
@@ -60,8 +60,8 @@
             ) {
                 Text(text = stringResource(R.string.volume_panel_dialog_settings_button))
             }
-            PlatformButton(onClick = viewModel::onDoneClicked) {
-                Text(text = stringResource(R.string.inline_done_button))
+            Button(onClick = viewModel::onDoneClicked) {
+                Text(stringResource(R.string.inline_done_button))
             }
         }
     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt
index d49fed5..b3fcc30 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt
@@ -27,6 +27,7 @@
 import androidx.compose.animation.slideInVertically
 import androidx.compose.animation.slideOutVertically
 import androidx.compose.animation.togetherWith
+import androidx.compose.foundation.basicMarquee
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
@@ -46,7 +47,6 @@
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.Expandable
 import com.android.systemui.common.ui.compose.Icon
@@ -78,8 +78,8 @@
             color = MaterialTheme.colorScheme.surface,
             shape = RoundedCornerShape(28.dp),
             onClick = { viewModel.onBarClick(it) },
-        ) {
-            Row {
+        ) { _ ->
+            Row(verticalAlignment = Alignment.CenterVertically) {
                 connectedDeviceViewModel?.let { ConnectedDeviceText(it) }
 
                 deviceIconViewModel?.let { ConnectedDeviceIcon(it) }
@@ -90,26 +90,23 @@
     @Composable
     private fun RowScope.ConnectedDeviceText(connectedDeviceViewModel: ConnectedDeviceViewModel) {
         Column(
-            modifier =
-                Modifier.weight(1f)
-                    .padding(start = 24.dp, top = 20.dp, bottom = 20.dp)
-                    .fillMaxHeight(),
+            modifier = Modifier.weight(1f).padding(start = 24.dp),
             verticalArrangement = Arrangement.spacedBy(4.dp),
         ) {
             Text(
-                connectedDeviceViewModel.label.toString(),
+                modifier = Modifier.basicMarquee(),
+                text = connectedDeviceViewModel.label.toString(),
                 style = MaterialTheme.typography.labelMedium,
                 color = MaterialTheme.colorScheme.onSurfaceVariant,
                 maxLines = 1,
-                overflow = TextOverflow.Ellipsis,
             )
             connectedDeviceViewModel.deviceName?.let {
                 Text(
-                    it.toString(),
+                    modifier = Modifier.basicMarquee(),
+                    text = it.toString(),
                     style = MaterialTheme.typography.titleMedium,
                     color = MaterialTheme.colorScheme.onSurface,
                     maxLines = 1,
-                    overflow = TextOverflow.Ellipsis,
                 )
             }
         }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
index a197a4b..4d810df 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
@@ -66,7 +66,7 @@
     modifier: Modifier = Modifier,
 ) {
     require(viewModels.isNotEmpty())
-    var isExpanded: Boolean by remember { mutableStateOf(false) }
+    var isExpanded: Boolean by remember(isExpandable) { mutableStateOf(!isExpandable) }
     val transition = updateTransition(isExpanded, label = "CollapsableSliders")
     Column(modifier = modifier) {
         Row(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt
index 5925b14..18a62dc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt
@@ -20,6 +20,7 @@
 import androidx.compose.animation.animateContentSize
 import androidx.compose.animation.expandVertically
 import androidx.compose.animation.shrinkVertically
+import androidx.compose.foundation.basicMarquee
 import androidx.compose.foundation.layout.Column
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
@@ -41,7 +42,7 @@
     modifier: Modifier = Modifier,
     sliderColors: PlatformSliderColors,
 ) {
-    var value by remember { mutableFloatStateOf(state.value) }
+    var value by remember(state.value) { mutableFloatStateOf(state.value) }
     PlatformSlider(
         modifier = modifier,
         value = value,
@@ -59,7 +60,12 @@
         colors = sliderColors,
         label = {
             Column(modifier = Modifier.animateContentSize()) {
-                Text(state.label, style = MaterialTheme.typography.titleMedium)
+                Text(
+                    modifier = Modifier.basicMarquee(),
+                    text = state.label,
+                    style = MaterialTheme.typography.titleMedium,
+                    maxLines = 1,
+                )
 
                 state.disabledMessage?.let { message ->
                     AnimatedVisibility(
@@ -67,7 +73,12 @@
                         enter = expandVertically { it },
                         exit = shrinkVertically { it },
                     ) {
-                        Text(text = message, style = MaterialTheme.typography.bodySmall)
+                        Text(
+                            modifier = Modifier.basicMarquee(),
+                            text = message,
+                            style = MaterialTheme.typography.bodySmall,
+                            maxLines = 1,
+                        )
                     }
                 }
             }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt
index 6213dc5..1ca18de 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.volume.panel.component.volume.ui.viewmodel.AudioVolumeComponentViewModel
 import com.android.systemui.volume.panel.ui.composable.ComposeVolumePanelUiComponent
 import com.android.systemui.volume.panel.ui.composable.VolumePanelComposeScope
+import com.android.systemui.volume.panel.ui.composable.isPortrait
 import javax.inject.Inject
 
 class VolumeSlidersComponent
@@ -50,7 +51,7 @@
             ColumnVolumeSliders(
                 viewModels = sliderViewModels,
                 sliderColors = PlatformSliderDefaults.defaultPlatformSliderColors(),
-                isExpandable = true,
+                isExpandable = isPortrait,
                 modifier = modifier.fillMaxWidth(),
             )
         }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/HorizontalVolumePanelContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/HorizontalVolumePanelContent.kt
index 0a651c8..ac5004e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/HorizontalVolumePanelContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/HorizontalVolumePanelContent.kt
@@ -21,7 +21,8 @@
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -36,7 +37,7 @@
     val spacing = 20.dp
     Row(modifier = modifier, horizontalArrangement = Arrangement.spacedBy(space = spacing)) {
         Column(
-            modifier = Modifier.weight(1f),
+            modifier = Modifier.weight(1f).verticalScroll(rememberScrollState()),
             verticalArrangement = Arrangement.spacedBy(spacing)
         ) {
             for (component in layout.contentComponents) {
@@ -47,7 +48,7 @@
         }
 
         Column(
-            modifier = Modifier.weight(1f),
+            modifier = Modifier.weight(1f).verticalScroll(rememberScrollState()),
             verticalArrangement = Arrangement.spacedBy(space = spacing, alignment = Alignment.Top)
         ) {
             for (component in layout.headerComponents) {
@@ -56,7 +57,7 @@
                 }
             }
             Row(
-                modifier = Modifier.fillMaxWidth().wrapContentHeight(),
+                modifier = Modifier.fillMaxWidth(),
                 horizontalArrangement = Arrangement.spacedBy(spacing),
             ) {
                 for (component in layout.footerComponents) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt
index 4d07379..dd76781 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt
@@ -22,6 +22,8 @@
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
@@ -33,7 +35,7 @@
     modifier: Modifier = Modifier,
 ) {
     Column(
-        modifier = modifier,
+        modifier = modifier.verticalScroll(rememberScrollState()),
         verticalArrangement = Arrangement.spacedBy(20.dp),
     ) {
         for (component in layout.headerComponents) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
index 8a1e6a8..910cd5e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
@@ -16,12 +16,13 @@
 
 package com.android.systemui.volume.panel.ui.composable
 
-import android.content.res.Configuration
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.isSystemInDarkTheme
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.displayCutout
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.heightIn
@@ -37,13 +38,17 @@
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.res.dimensionResource
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.max
 import com.android.compose.theme.PlatformTheme
 import com.android.systemui.res.R
 import com.android.systemui.volume.panel.ui.layout.ComponentsLayout
 import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelState
 import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel
+import kotlin.math.max
 
 private val padding = 24.dp
 
@@ -66,12 +71,12 @@
         val components by viewModel.componentsLayout.collectAsState(null)
 
         with(VolumePanelComposeScope(state)) {
-            var boxModifier = modifier.fillMaxSize().clickable(onClick = onDismiss)
-            if (!isPortrait) {
-                boxModifier = boxModifier.padding(horizontal = 48.dp)
-            }
             Box(
-                modifier = boxModifier,
+                modifier =
+                    modifier
+                        .fillMaxSize()
+                        .clickable(onClick = onDismiss)
+                        .volumePanelPaddings(isPortrait = isPortrait),
                 contentAlignment = Alignment.BottomCenter,
             ) {
                 val radius = dimensionResource(R.dimen.volume_panel_corner_radius)
@@ -81,8 +86,8 @@
                             interactionSource = null,
                             indication = null,
                             onClick = {
-                                // prevent windowCloseOnTouchOutside from dismissing when tapped on
-                                // the panel itself.
+                                // prevent windowCloseOnTouchOutside from dismissing when tapped
+                                // on the panel itself.
                             },
                         ),
                     shape = RoundedCornerShape(topStart = radius, topEnd = radius),
@@ -111,17 +116,31 @@
     layout: ComponentsLayout,
     modifier: Modifier = Modifier
 ) {
-    var columnModifier = modifier.widthIn(max = 800.dp)
-    if (!isLargeScreen && orientation != Configuration.ORIENTATION_PORTRAIT) {
-        columnModifier = columnModifier.heightIn(max = 332.dp)
-    }
-    Column(modifier = columnModifier, verticalArrangement = Arrangement.spacedBy(padding)) {
-        if (orientation == Configuration.ORIENTATION_PORTRAIT || isLargeScreen) {
-            VerticalVolumePanelContent(layout)
+    val arrangement: Arrangement.Vertical =
+        if (isLargeScreen) {
+            Arrangement.spacedBy(20.dp)
         } else {
-            HorizontalVolumePanelContent(layout)
+            if (isPortrait) Arrangement.spacedBy(padding) else Arrangement.spacedBy(4.dp)
         }
-        BottomBar(layout = layout, modifier = Modifier)
+    Column(
+        modifier = modifier.widthIn(max = 800.dp),
+        verticalArrangement = arrangement,
+    ) {
+        if (isPortrait || isLargeScreen) {
+            VerticalVolumePanelContent(
+                modifier = Modifier.weight(weight = 1f, fill = false),
+                layout = layout
+            )
+        } else {
+            HorizontalVolumePanelContent(
+                modifier = Modifier.weight(weight = 1f, fill = false).heightIn(max = 212.dp),
+                layout = layout,
+            )
+        }
+        BottomBar(
+            modifier = Modifier,
+            layout = layout,
+        )
     }
 }
 
@@ -141,3 +160,28 @@
         }
     }
 }
+
+/**
+ * Makes sure volume panel stays symmetrically in the middle of the screen while still avoiding
+ * being under the cutouts.
+ */
+@Composable
+private fun Modifier.volumePanelPaddings(isPortrait: Boolean): Modifier {
+    val cutout = WindowInsets.displayCutout
+    return with(LocalDensity.current) {
+        val horizontalCutout =
+            max(
+                cutout.getLeft(density = this, layoutDirection = LocalLayoutDirection.current),
+                cutout.getRight(density = this, layoutDirection = LocalLayoutDirection.current)
+            )
+        val minHorizontalPadding = if (isPortrait) 0.dp else 48.dp
+        val horizontalPadding = max(horizontalCutout.toDp(), minHorizontalPadding)
+
+        padding(
+            start = horizontalPadding,
+            top = cutout.getTop(this).toDp(),
+            end = horizontalPadding,
+            bottom = cutout.getBottom(this).toDp(),
+        )
+    }
+}
diff --git a/packages/SystemUI/compose/features/tests/Android.bp b/packages/SystemUI/compose/features/tests/Android.bp
deleted file mode 100644
index 69b18c4..0000000
--- a/packages/SystemUI/compose/features/tests/Android.bp
+++ /dev/null
@@ -1,50 +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 {
-    default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
-    // 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"],
-}
-
-// TODO(b/230606318): Make those host tests instead of device tests.
-android_test {
-    name: "SystemUIComposeFeaturesTests",
-    use_resource_processor: true,
-    manifest: "AndroidManifest.xml",
-    test_suites: ["device-tests"],
-    sdk_version: "current",
-    certificate: "platform",
-
-    srcs: [
-        "src/**/*.kt",
-    ],
-
-    static_libs: [
-        "SystemUIComposeFeatures",
-
-        "androidx.test.runner",
-        "androidx.test.ext.junit",
-
-        "androidx.compose.runtime_runtime",
-        "androidx.compose.ui_ui-test-junit4",
-        "androidx.compose.ui_ui-test-manifest",
-    ],
-
-    kotlincflags: ["-Xjvm-default=all"],
-}
diff --git a/packages/SystemUI/compose/features/tests/AndroidManifest.xml b/packages/SystemUI/compose/features/tests/AndroidManifest.xml
deleted file mode 100644
index fc337fb..0000000
--- a/packages/SystemUI/compose/features/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    package="com.android.systemui.compose.features.tests" >
-
-    <application
-        android:name="android.app.Application"
-        android:appComponentFactory="androidx.core.app.AppComponentFactory"
-        tools:replace="android:name,android:appComponentFactory">
-        <uses-library android:name="android.test.runner" />
-
-        <!-- Disable providers from SystemUI -->
-        <provider android:name="com.android.systemui.keyguard.KeyguardSliceProvider"
-            android:authorities="com.android.systemui.test.keyguard.disabled"
-            android:enabled="false"
-            tools:replace="android:authorities"
-            tools:node="remove" />
-        <provider android:name="com.android.systemui.keyguard.CustomizationProvider"
-            android:authorities="com.android.systemui.test.keyguard.quickaffordance.disabled"
-            android:enabled="false"
-            tools:replace="android:authorities"
-            tools:node="remove" />
-        <provider android:name="com.android.systemui.people.PeopleProvider"
-            android:authorities="com.android.systemui.test.people.disabled"
-            android:enabled="false"
-            tools:replace="android:authorities"
-            tools:node="remove" />
-        <provider android:name="androidx.core.content.FileProvider"
-            android:authorities="com.android.systemui.test.fileprovider.disabled"
-            android:enabled="false"
-            tools:replace="android:authorities"
-            tools:node="remove"/>
-    </application>
-
-    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.systemui.compose.features.tests"
-                     android:label="Tests for SystemUIComposeFeatures"/>
-
-</manifest>
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/TEST_MAPPING b/packages/SystemUI/compose/scene/TEST_MAPPING
index f644a23..f9424ed 100644
--- a/packages/SystemUI/compose/scene/TEST_MAPPING
+++ b/packages/SystemUI/compose/scene/TEST_MAPPING
@@ -23,17 +23,6 @@
       ]
     },
     {
-      "name": "SystemUIComposeFeaturesTests",
-      "options": [
-        {
-          "exclude-annotation": "org.junit.Ignore"
-        },
-        {
-          "exclude-annotation": "androidx.test.filters.FlakyTest"
-        }
-      ]
-    },
-    {
       "name": "SystemUIComposeGalleryTests",
       "options": [
         {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
similarity index 67%
rename from packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
rename to packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index 76e7c95..b94e49b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -27,7 +27,6 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.round
@@ -37,41 +36,38 @@
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.launch
 
-internal class SceneGestureHandler(
+interface DraggableHandler {
+    /**
+     * Start a drag in the given [startedPosition], with the given [overSlop] and number of
+     * [pointersDown].
+     *
+     * The returned [DragController] should be used to continue or stop the drag.
+     */
+    fun onDragStarted(startedPosition: Offset?, overSlop: Float, pointersDown: Int): DragController
+}
+
+/**
+ * The [DragController] provides control over the transition between two scenes through the [onDrag]
+ * and [onStop] methods.
+ */
+interface DragController {
+    /** Drag the current scene by [delta] pixels. */
+    fun onDrag(delta: Float)
+
+    /** Starts a transition to a target scene. */
+    fun onStop(velocity: Float, canChangeScene: Boolean)
+}
+
+internal class DraggableHandlerImpl(
     internal val layoutImpl: SceneTransitionLayoutImpl,
     internal val orientation: Orientation,
-    private val coroutineScope: CoroutineScope,
-) {
-    private val layoutState = layoutImpl.state
-    val draggable: DraggableHandler = SceneDraggableHandler(this)
+    internal val coroutineScope: CoroutineScope,
+) : DraggableHandler {
+    /** The [DraggableHandler] can only have one active [DragController] at a time. */
+    private var dragController: DragControllerImpl? = null
 
-    private var _swipeTransition: SwipeTransition? = null
-    private var swipeTransition: SwipeTransition
-        get() = _swipeTransition ?: error("SwipeTransition needs to be initialized")
-        set(value) {
-            _swipeTransition = value
-        }
-
-    private fun updateTransition(newTransition: SwipeTransition, force: Boolean = false) {
-        if (isDrivingTransition || force) {
-            layoutState.startTransition(newTransition, newTransition.key)
-
-            // Initialize SwipeTransition.swipeSpec. Note that this must be called right after
-            // layoutState.startTransition() is called, because it computes the
-            // layoutState.transformationSpec().
-            newTransition.swipeSpec =
-                layoutState.transformationSpec.swipeSpec ?: layoutState.transitions.defaultSwipeSpec
-        } else {
-            // We were not driving the transition and we don't force the update, so the spec won't
-            // be used and it doesn't matter which one we set here.
-            newTransition.swipeSpec = SceneTransitions.DefaultSwipeSpec
-        }
-
-        swipeTransition = newTransition
-    }
-
-    internal val isDrivingTransition
-        get() = layoutState.transitionState == _swipeTransition
+    internal val isDrivingTransition: Boolean
+        get() = dragController?.isDrivingTransition == true
 
     /**
      * The velocity threshold at which the intent of the user is to swipe up or down. It is the same
@@ -84,14 +80,9 @@
      * The positional threshold at which the intent of the user is to swipe to the next scene. It is
      * the same as SwipeableV2Defaults.PositionalThreshold.
      */
-    private val positionalThreshold
+    internal val positionalThreshold
         get() = with(layoutImpl.density) { 56.dp.toPx() }
 
-    internal var currentSource: Any? = null
-
-    /** The [Swipes] associated to the current gesture. */
-    private var swipes: Swipes? = null
-
     /**
      * Whether we should immediately intercept a gesture.
      *
@@ -100,35 +91,52 @@
      */
     internal fun shouldImmediatelyIntercept(startedPosition: Offset?): Boolean {
         // We don't intercept the touch if we are not currently driving the transition.
-        if (!isDrivingTransition) {
+        val dragController = dragController
+        if (dragController?.isDrivingTransition != true) {
             return false
         }
 
         // Only intercept the current transition if one of the 2 swipes results is also a transition
         // between the same pair of scenes.
+        val swipeTransition = dragController.swipeTransition
         val fromScene = swipeTransition._currentScene
         val swipes = computeSwipes(fromScene, startedPosition, pointersDown = 1)
-        val (upOrLeft, downOrRight) = computeSwipesResults(fromScene, swipes)
+        val (upOrLeft, downOrRight) = swipes.computeSwipesResults(fromScene)
         return (upOrLeft != null &&
             swipeTransition.isTransitioningBetween(fromScene.key, upOrLeft.toScene)) ||
             (downOrRight != null &&
                 swipeTransition.isTransitioningBetween(fromScene.key, downOrRight.toScene))
     }
 
-    internal fun onDragStarted(pointersDown: Int, startedPosition: Offset?, overSlop: Float) {
+    override fun onDragStarted(
+        startedPosition: Offset?,
+        overSlop: Float,
+        pointersDown: Int,
+    ): DragController {
         if (overSlop == 0f) {
-            check(isDrivingTransition) {
-                "onDragStarted() called while isDrivingTransition=false overSlop=0f"
+            val oldDragController = dragController
+            check(oldDragController != null && oldDragController.isDrivingTransition) {
+                val isActive = oldDragController?.isDrivingTransition
+                "onDragStarted(overSlop=0f) requires an active dragController, but was $isActive"
             }
 
             // This [transition] was already driving the animation: simply take over it.
             // Stop animating and start from where the current offset.
-            swipeTransition.cancelOffsetAnimation()
-            swipes!!.updateSwipesResults(swipeTransition._fromScene)
-            return
+            oldDragController.swipeTransition.cancelOffsetAnimation()
+
+            // We need to recompute the swipe results since this is a new gesture, and the
+            // fromScene.userActions may have changed.
+            val swipes = oldDragController.swipes
+            swipes.updateSwipesResults(oldDragController.swipeTransition._fromScene)
+
+            // A new gesture should always create a new SwipeTransition. This way there cannot be
+            // different gestures controlling the same transition.
+            val swipeTransition = SwipeTransition(oldDragController.swipeTransition)
+            swipes.updateSwipesResults(fromScene = swipeTransition._fromScene)
+            return updateDragController(swipes, swipeTransition)
         }
 
-        val transitionState = layoutState.transitionState
+        val transitionState = layoutImpl.state.transitionState
         if (transitionState is TransitionState.Transition) {
             // TODO(b/290184746): Better handle interruptions here if state != idle.
             Log.w(
@@ -140,24 +148,27 @@
         }
 
         val fromScene = layoutImpl.scene(transitionState.currentScene)
-        val newSwipes = computeSwipes(fromScene, startedPosition, pointersDown)
-        swipes = newSwipes
-        val result = newSwipes.findUserActionResult(fromScene, overSlop, true)
+        val swipes = computeSwipes(fromScene, startedPosition, pointersDown)
+        val result = swipes.findUserActionResult(fromScene, overSlop, true)
 
         // As we were unable to locate a valid target scene, the initial SwipeTransition cannot be
-        // defined.
-        if (result == null) return
+        // defined. Consequently, a simple NoOp Controller will be returned.
+        if (result == null) return NoOpDragController
 
-        val newSwipeTransition =
-            SwipeTransition(
-                fromScene = fromScene,
-                result = result,
-                swipes = newSwipes,
-                layoutImpl = layoutImpl,
-                orientation = orientation
-            )
+        return updateDragController(
+            swipes = swipes,
+            swipeTransition = SwipeTransition(fromScene, result, swipes, layoutImpl, orientation)
+        )
+    }
 
-        updateTransition(newSwipeTransition, force = true)
+    private fun updateDragController(
+        swipes: Swipes,
+        swipeTransition: SwipeTransition
+    ): DragController {
+        val newDragController = DragControllerImpl(this, swipes, swipeTransition)
+        newDragController.updateTransition(swipeTransition, force = true)
+        dragController = newDragController
+        return newDragController
     }
 
     private fun computeSwipes(
@@ -214,7 +225,58 @@
         }
     }
 
-    internal fun onDrag(delta: Float) {
+    companion object {
+        private const val TAG = "DraggableHandlerImpl"
+    }
+}
+
+/** @param swipes The [Swipes] associated to the current gesture. */
+private class DragControllerImpl(
+    private val draggableHandler: DraggableHandlerImpl,
+    val swipes: Swipes,
+    var swipeTransition: SwipeTransition,
+) : DragController {
+    val layoutState = draggableHandler.layoutImpl.state
+
+    /**
+     * Whether this handle is active. If this returns false, calling [onDrag] and [onStop] will do
+     * nothing. We should have only one active controller at a time
+     */
+    val isDrivingTransition: Boolean
+        get() = layoutState.transitionState == swipeTransition
+
+    init {
+        check(!isDrivingTransition) { "Multiple controllers with the same SwipeTransition" }
+    }
+
+    fun updateTransition(newTransition: SwipeTransition, force: Boolean = false) {
+        if (isDrivingTransition || force) {
+            layoutState.startTransition(newTransition, newTransition.key)
+
+            // Initialize SwipeTransition.transformationSpec and .swipeSpec. Note that this must be
+            // called right after layoutState.startTransition() is called, because it computes the
+            // current layoutState.transformationSpec().
+            val transformationSpec = layoutState.transformationSpec
+            newTransition.transformationSpec = transformationSpec
+            newTransition.swipeSpec =
+                transformationSpec.swipeSpec ?: layoutState.transitions.defaultSwipeSpec
+        } else {
+            // We were not driving the transition and we don't force the update, so the specs won't
+            // be used and it doesn't matter which ones we set here.
+            newTransition.transformationSpec = TransformationSpec.Empty
+            newTransition.swipeSpec = SceneTransitions.DefaultSwipeSpec
+        }
+
+        swipeTransition = newTransition
+    }
+
+    /**
+     * We receive a [delta] that can be consumed to change the offset of the current
+     * [SwipeTransition].
+     *
+     * @return the consumed delta
+     */
+    override fun onDrag(delta: Float) {
         if (delta == 0f || !isDrivingTransition) return
         swipeTransition.dragOffset += delta
 
@@ -223,14 +285,14 @@
 
         val isNewFromScene = fromScene.key != swipeTransition.fromScene
         val result =
-            swipes!!.findUserActionResult(
+            swipes.findUserActionResult(
                 fromScene = fromScene,
                 directionOffset = swipeTransition.dragOffset,
                 updateSwipesResults = isNewFromScene
             )
 
         if (result == null) {
-            onDragStopped(velocity = delta, canChangeScene = true)
+            onStop(velocity = delta, canChangeScene = true)
             return
         }
 
@@ -241,36 +303,20 @@
                 result.toScene != swipeTransition.toScene ||
                 result.transitionKey != swipeTransition.key
         ) {
-            val newSwipeTransition =
+            val swipeTransition =
                 SwipeTransition(
                         fromScene = fromScene,
                         result = result,
-                        swipes = swipes!!,
-                        layoutImpl = layoutImpl,
-                        orientation = orientation
+                        swipes = swipes,
+                        layoutImpl = draggableHandler.layoutImpl,
+                        orientation = draggableHandler.orientation,
                     )
                     .apply { dragOffset = swipeTransition.dragOffset }
 
-            updateTransition(newSwipeTransition)
+            updateTransition(swipeTransition)
         }
     }
 
-    private fun computeSwipesResults(
-        fromScene: Scene,
-        swipes: Swipes
-    ): Pair<UserActionResult?, UserActionResult?> {
-        val userActions = fromScene.userActions
-        fun sceneToSwipePair(swipe: Swipe?): UserActionResult? {
-            return userActions[swipe ?: return null]
-        }
-
-        val upOrLeftResult =
-            sceneToSwipePair(swipes.upOrLeft) ?: sceneToSwipePair(swipes.upOrLeftNoSource)
-        val downOrRightResult =
-            sceneToSwipePair(swipes.downOrRight) ?: sceneToSwipePair(swipes.downOrRightNoSource)
-        return Pair(upOrLeftResult, downOrRightResult)
-    }
-
     /**
      * Change fromScene in the case where the user quickly swiped multiple times in the same
      * direction to accelerate the transition from A => B then B => C.
@@ -285,28 +331,37 @@
     ): Pair<Scene, Float> {
         val toScene = swipeTransition._toScene
         val fromScene = swipeTransition._fromScene
-        val absoluteDistance = swipeTransition.distance.absoluteValue
+        val distance = swipeTransition.distance()
 
-        // If the swipe was not committed, don't do anything.
-        if (swipeTransition._currentScene != toScene) {
+        // If the swipe was not committed or if the swipe distance is not computed yet, don't do
+        // anything.
+        if (
+            swipeTransition._currentScene != toScene ||
+                distance == SwipeTransition.DistanceUnspecified
+        ) {
             return fromScene to 0f
         }
 
         // If the offset is past the distance then let's change fromScene so that the user can swipe
         // to the next screen or go back to the previous one.
         val offset = swipeTransition.dragOffset
-        return if (offset <= -absoluteDistance && swipes!!.upOrLeftResult?.toScene == toScene.key) {
+        val absoluteDistance = distance.absoluteValue
+        return if (offset <= -absoluteDistance && swipes.upOrLeftResult?.toScene == toScene.key) {
             toScene to absoluteDistance
-        } else if (
-            offset >= absoluteDistance && swipes!!.downOrRightResult?.toScene == toScene.key
-        ) {
+        } else if (offset >= absoluteDistance && swipes.downOrRightResult?.toScene == toScene.key) {
             toScene to -absoluteDistance
         } else {
             fromScene to 0f
         }
     }
 
-    internal fun onDragStopped(velocity: Float, canChangeScene: Boolean) {
+    private fun snapToScene(scene: SceneKey) {
+        if (!isDrivingTransition) return
+        swipeTransition.cancelOffsetAnimation()
+        layoutState.finishTransition(swipeTransition, idleScene = scene)
+    }
+
+    override fun onStop(velocity: Float, canChangeScene: Boolean) {
         // The state was changed since the drag started; don't do anything.
         if (!isDrivingTransition) {
             return
@@ -325,16 +380,16 @@
             // immediately go back B => A.
             if (targetScene != swipeTransition._currentScene) {
                 swipeTransition._currentScene = targetScene
-                with(layoutImpl.state) { coroutineScope.onChangeScene(targetScene.key) }
+                with(draggableHandler.layoutImpl.state) {
+                    draggableHandler.coroutineScope.onChangeScene(targetScene.key)
+                }
             }
 
             swipeTransition.animateOffset(
-                coroutineScope = coroutineScope,
+                coroutineScope = draggableHandler.coroutineScope,
                 initialVelocity = velocity,
                 targetOffset = targetOffset,
-                onAnimationCompleted = {
-                    layoutState.finishTransition(swipeTransition, idleScene = targetScene.key)
-                }
+                onAnimationCompleted = { snapToScene(targetScene.key) }
             )
         }
 
@@ -347,16 +402,17 @@
 
             // Compute the destination scene (and therefore offset) to settle in.
             val offset = swipeTransition.dragOffset
-            val distance = swipeTransition.distance
+            val distance = swipeTransition.distance()
             var targetScene: Scene
             var targetOffset: Float
             if (
-                shouldCommitSwipe(
-                    offset,
-                    distance,
-                    velocity,
-                    wasCommitted = swipeTransition._currentScene == toScene,
-                )
+                distance != SwipeTransition.DistanceUnspecified &&
+                    shouldCommitSwipe(
+                        offset,
+                        distance,
+                        velocity,
+                        wasCommitted = swipeTransition._currentScene == toScene,
+                    )
             ) {
                 targetScene = toScene
                 targetOffset = distance
@@ -372,7 +428,15 @@
                 // We wanted to change to a new scene but we are not allowed to, so we animate back
                 // to the current scene.
                 targetScene = swipeTransition._currentScene
-                targetOffset = if (targetScene == fromScene) 0f else distance
+                targetOffset =
+                    if (targetScene == fromScene) {
+                        0f
+                    } else {
+                        check(distance != SwipeTransition.DistanceUnspecified) {
+                            "distance is equal to ${SwipeTransition.DistanceUnspecified}"
+                        }
+                        distance
+                    }
             }
 
             animateTo(targetScene = targetScene, targetOffset = targetOffset)
@@ -384,10 +448,10 @@
 
             if (startFromIdlePosition) {
                 // If there is a target scene, we start the overscroll animation.
-                val result = swipes!!.findUserActionResultStrict(velocity)
+                val result = swipes.findUserActionResultStrict(velocity)
                 if (result == null) {
                     // We will not animate
-                    layoutState.finishTransition(swipeTransition, idleScene = fromScene.key)
+                    snapToScene(fromScene.key)
                     return
                 }
 
@@ -395,9 +459,9 @@
                     SwipeTransition(
                             fromScene = fromScene,
                             result = result,
-                            swipes = swipes!!,
-                            layoutImpl = layoutImpl,
-                            orientation = orientation
+                            swipes = swipes,
+                            layoutImpl = draggableHandler.layoutImpl,
+                            orientation = draggableHandler.orientation,
                         )
                         .apply { _currentScene = swipeTransition._currentScene }
 
@@ -424,6 +488,9 @@
             return (offset - distance).absoluteValue < offset.absoluteValue
         }
 
+        val velocityThreshold = draggableHandler.velocityThreshold
+        val positionalThreshold = draggableHandler.positionalThreshold
+
         // Swiping up or left.
         if (distance < 0f) {
             return if (offset > 0f || velocity >= velocityThreshold) {
@@ -444,10 +511,6 @@
                 isCloserToTarget()
         }
     }
-
-    companion object {
-        private const val TAG = "SceneGestureHandler"
-    }
 }
 
 private fun SwipeTransition(
@@ -459,42 +522,64 @@
 ): SwipeTransition {
     val upOrLeftResult = swipes.upOrLeftResult
     val downOrRightResult = swipes.downOrRightResult
-    val userActionDistance = result.distance ?: DefaultSwipeDistance
-    val absoluteDistance =
-        with(userActionDistance) {
-            layoutImpl.density.absoluteDistance(fromScene.targetSize, orientation)
+    val isUpOrLeft =
+        when (result) {
+            upOrLeftResult -> true
+            downOrRightResult -> false
+            else -> error("Unknown result $result ($upOrLeftResult $downOrRightResult)")
         }
 
     return SwipeTransition(
         key = result.transitionKey,
         _fromScene = fromScene,
         _toScene = layoutImpl.scene(result.toScene),
-        distance =
-            when (result) {
-                upOrLeftResult -> -absoluteDistance
-                downOrRightResult -> absoluteDistance
-                else -> error("Unknown result $result ($upOrLeftResult $downOrRightResult)")
-            },
+        userActionDistanceScope = layoutImpl.userActionDistanceScope,
+        orientation = orientation,
+        isUpOrLeft = isUpOrLeft,
     )
 }
 
+private fun SwipeTransition(old: SwipeTransition): SwipeTransition {
+    return SwipeTransition(
+            key = old.key,
+            _fromScene = old._fromScene,
+            _toScene = old._toScene,
+            userActionDistanceScope = old.userActionDistanceScope,
+            orientation = old.orientation,
+            isUpOrLeft = old.isUpOrLeft
+        )
+        .apply {
+            _currentScene = old._currentScene
+            dragOffset = old.dragOffset
+        }
+}
+
 private class SwipeTransition(
     val key: TransitionKey?,
     val _fromScene: Scene,
     val _toScene: Scene,
-    /**
-     * The signed distance between [fromScene] and [toScene]. It is negative if [fromScene] is above
-     * or to the left of [toScene]
-     */
-    val distance: Float,
-) : TransitionState.Transition(_fromScene.key, _toScene.key) {
+    val userActionDistanceScope: UserActionDistanceScope,
+    override val orientation: Orientation,
+    override val isUpOrLeft: Boolean,
+) :
+    TransitionState.Transition(_fromScene.key, _toScene.key),
+    TransitionState.HasOverscrollProperties {
     var _currentScene by mutableStateOf(_fromScene)
     override val currentScene: SceneKey
         get() = _currentScene.key
 
     override val progress: Float
         get() {
+            // Important: If we are going to return early because distance is equal to 0, we should
+            // still make sure we read the offset before returning so that the calling code still
+            // subscribes to the offset value.
             val offset = if (isAnimatingOffset) offsetAnimatable.value else dragOffset
+
+            val distance = distance()
+            if (distance == DistanceUnspecified) {
+                return 0f
+            }
+
             return offset / distance
         }
 
@@ -518,9 +603,50 @@
     /** Job to check that there is at most one offset animation in progress. */
     private var offsetAnimationJob: Job? = null
 
+    /**
+     * The [TransformationSpecImpl] associated to this transition.
+     *
+     * Note: This is lateinit because this [SwipeTransition] is needed by
+     * [BaseSceneTransitionLayoutState] to compute the [TransitionSpec], and it will be set right
+     * after [BaseSceneTransitionLayoutState.startTransition] is called with this transition.
+     */
+    lateinit var transformationSpec: TransformationSpecImpl
+
     /** The spec to use when animating this transition to either [fromScene] or [toScene]. */
     lateinit var swipeSpec: SpringSpec<Float>
 
+    private var lastDistance = DistanceUnspecified
+
+    /**
+     * The signed distance between [fromScene] and [toScene]. It is negative if [fromScene] is above
+     * or to the left of [toScene].
+     *
+     * Note that this distance can be equal to [DistanceUnspecified] during the first frame of a
+     * transition when the distance depends on the size or position of an element that is composed
+     * in the scene we are going to.
+     */
+    fun distance(): Float {
+        if (lastDistance != DistanceUnspecified) {
+            return lastDistance
+        }
+
+        val absoluteDistance =
+            with(transformationSpec.distance ?: DefaultSwipeDistance) {
+                userActionDistanceScope.absoluteDistance(
+                    _fromScene.targetSize,
+                    orientation,
+                )
+            }
+
+        if (absoluteDistance <= 0f) {
+            return DistanceUnspecified
+        }
+
+        val distance = if (isUpOrLeft) -absoluteDistance else absoluteDistance
+        lastDistance = distance
+        return distance
+    }
+
     /** Ends any previous [offsetAnimationJob] and runs the new [job]. */
     private fun startOffsetAnimation(job: () -> Job) {
         cancelOffsetAnimation()
@@ -563,6 +689,7 @@
         }
         isAnimatingOffset = true
 
+        val animationSpec = transformationSpec
         offsetAnimatable.animateTo(
             targetValue = targetOffset,
             animationSpec = swipeSpec,
@@ -571,10 +698,14 @@
 
         finishOffsetAnimation()
     }
+
+    companion object {
+        const val DistanceUnspecified = 0f
+    }
 }
 
 private object DefaultSwipeDistance : UserActionDistance {
-    override fun Density.absoluteDistance(
+    override fun UserActionDistanceScope.absoluteDistance(
         fromSceneSize: IntSize,
         orientation: Orientation,
     ): Float {
@@ -661,40 +792,16 @@
     }
 }
 
-private class SceneDraggableHandler(
-    private val gestureHandler: SceneGestureHandler,
-) : DraggableHandler {
-    private val source = this
-
-    override fun onDragStarted(startedPosition: Offset, overSlop: Float, pointersDown: Int) {
-        gestureHandler.currentSource = source
-        gestureHandler.onDragStarted(pointersDown, startedPosition, overSlop)
-    }
-
-    override fun onDelta(pixels: Float) {
-        if (gestureHandler.currentSource == source) {
-            gestureHandler.onDrag(delta = pixels)
-        }
-    }
-
-    override fun onDragStopped(velocity: Float) {
-        if (gestureHandler.currentSource == source) {
-            gestureHandler.currentSource = null
-            gestureHandler.onDragStopped(velocity = velocity, canChangeScene = true)
-        }
-    }
-}
-
-internal class SceneNestedScrollHandler(
+internal class NestedScrollHandlerImpl(
     private val layoutImpl: SceneTransitionLayoutImpl,
     private val orientation: Orientation,
     private val topOrLeftBehavior: NestedScrollBehavior,
     private val bottomOrRightBehavior: NestedScrollBehavior,
-) : NestedScrollHandler {
+) {
     private val layoutState = layoutImpl.state
-    private val gestureHandler = layoutImpl.gestureHandler(orientation)
+    private val draggableHandler = layoutImpl.draggableHandler(orientation)
 
-    override val connection: PriorityNestedScrollConnection = nestedScrollConnection()
+    val connection: PriorityNestedScrollConnection = nestedScrollConnection()
 
     private fun nestedScrollConnection(): PriorityNestedScrollConnection {
         // If we performed a long gesture before entering priority mode, we would have to avoid
@@ -722,17 +829,24 @@
             )
 
         fun hasNextScene(amount: Float): Boolean {
-            val fromScene = layoutImpl.scene(layoutState.transitionState.currentScene)
+            val transitionState = layoutState.transitionState
+            val scene = transitionState.currentScene
+            val fromScene = layoutImpl.scene(scene)
             val nextScene =
                 when {
                     amount < 0f -> fromScene.userActions[actionUpOrLeft]
                     amount > 0f -> fromScene.userActions[actionDownOrRight]
                     else -> null
                 }
-            return nextScene != null
+            if (nextScene != null) return true
+
+            if (transitionState !is TransitionState.Idle) return false
+
+            val overscrollSpec = layoutImpl.state.transitions.overscrollSpec(scene, orientation)
+            return overscrollSpec != null
         }
 
-        val source = this
+        var dragController: DragController? = null
         var isIntercepting = false
 
         return PriorityNestedScrollConnection(
@@ -743,7 +857,7 @@
                 val canInterceptSwipeTransition =
                     canChangeScene &&
                         offsetAvailable != 0f &&
-                        gestureHandler.shouldImmediatelyIntercept(startedPosition = null)
+                        draggableHandler.shouldImmediatelyIntercept(startedPosition = null)
                 if (!canInterceptSwipeTransition) return@PriorityNestedScrollConnection false
 
                 val threshold = layoutImpl.transitionInterceptionThreshold
@@ -817,34 +931,28 @@
             canContinueScroll = { true },
             canScrollOnFling = false,
             onStart = { offsetAvailable ->
-                gestureHandler.currentSource = source
-                gestureHandler.onDragStarted(
-                    pointersDown = 1,
-                    startedPosition = null,
-                    overSlop = if (isIntercepting) 0f else offsetAvailable,
-                )
+                dragController =
+                    draggableHandler.onDragStarted(
+                        pointersDown = 1,
+                        startedPosition = null,
+                        overSlop = if (isIntercepting) 0f else offsetAvailable,
+                    )
             },
             onScroll = { offsetAvailable ->
-                if (gestureHandler.currentSource != source) {
-                    return@PriorityNestedScrollConnection 0f
-                }
+                val controller = dragController ?: error("Should be called after onStart")
 
                 // TODO(b/297842071) We should handle the overscroll or slow drag if the gesture is
                 // initiated in a nested child.
-                gestureHandler.onDrag(offsetAvailable)
+                controller.onDrag(delta = offsetAvailable)
 
                 offsetAvailable
             },
             onStop = { velocityAvailable ->
-                if (gestureHandler.currentSource != source) {
-                    return@PriorityNestedScrollConnection 0f
-                }
+                val controller = dragController ?: error("Should be called after onStart")
 
-                gestureHandler.onDragStopped(
-                    velocity = velocityAvailable,
-                    canChangeScene = canChangeScene
-                )
+                controller.onStop(velocity = velocityAvailable, canChangeScene = canChangeScene)
 
+                dragController = null
                 // The onDragStopped animation consumes any remaining velocity.
                 velocityAvailable
             },
@@ -859,3 +967,9 @@
 // TODO(b/290184746): Have a better default visibility threshold which takes the swipe distance into
 // account instead.
 internal const val OffsetVisibilityThreshold = 0.5f
+
+private object NoOpDragController : DragController {
+    override fun onDrag(delta: Float) {}
+
+    override fun onStop(velocity: Float, canChangeScene: Boolean) {}
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 2e781e6..c7186da 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -39,7 +39,6 @@
 import androidx.compose.ui.node.DrawModifierNode
 import androidx.compose.ui.node.ModifierNodeElement
 import androidx.compose.ui.platform.testTag
-import androidx.compose.ui.semantics.testTag
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.round
@@ -204,6 +203,17 @@
         measurable: Measurable,
         constraints: Constraints,
     ): MeasureResult {
+        val overscrollScene = layoutImpl.state.currentOverscrollSpec?.scene
+        if (overscrollScene != null && overscrollScene != scene.key) {
+            // There is an overscroll in progress on another scene
+            // By measuring composable elements, Compose can cache relevant information.
+            // This reduces the need for re-measure when users return from an overscroll animation.
+            val placeable = measurable.measure(constraints)
+            return layout(placeable.width, placeable.height) {
+                // We don't want to draw it, no need to place the element.
+            }
+        }
+
         val placeable = measure(layoutImpl, scene, element, sceneState, measurable, constraints)
         return layout(placeable.width, placeable.height) {
             place(layoutImpl, scene, element, sceneState, placeable, placementScope = this)
@@ -253,11 +263,13 @@
 ): Boolean {
     val transition = layoutImpl.state.currentTransition
 
-    // Always draw the element if there is no ongoing transition or if the element is not shared.
+    // Always draw the element if there is no ongoing transition or if the element is not shared or
+    // if the current scene is the one that is currently over scrolling with [OverscrollSpec].
     if (
         transition == null ||
             transition.fromScene !in element.sceneStates ||
-            transition.toScene !in element.sceneStates
+            transition.toScene !in element.sceneStates ||
+            layoutImpl.state.currentOverscrollSpec?.scene == scene.key
     ) {
         return true
     }
@@ -286,12 +298,14 @@
     val fromScene = transition.fromScene
     val toScene = transition.toScene
 
-    return scenePicker.sceneDuringTransition(
-        element = element,
-        transition = transition,
-        fromSceneZIndex = layoutImpl.scenes.getValue(fromScene).zIndex,
-        toSceneZIndex = layoutImpl.scenes.getValue(toScene).zIndex,
-    ) == scene
+    val chosenByPicker =
+        scenePicker.sceneDuringTransition(
+            element = element,
+            transition = transition,
+            fromSceneZIndex = layoutImpl.scenes.getValue(fromScene).zIndex,
+            toSceneZIndex = layoutImpl.scenes.getValue(toScene).zIndex,
+        ) == scene
+    return chosenByPicker || layoutImpl.state.currentOverscrollSpec?.scene == scene
 }
 
 private fun isSharedElementEnabled(
@@ -549,6 +563,40 @@
         return idleValue
     }
 
+    if (transition is TransitionState.HasOverscrollProperties) {
+        val overscroll = layoutImpl.state.currentOverscrollSpec
+        if (overscroll?.scene == scene.key) {
+            val elementSpec = overscroll.transformationSpec.transformations(element.key, scene.key)
+            val propertySpec = transformation(elementSpec) ?: return currentValue()
+            val overscrollState = checkNotNull(if (scene.key == toScene) toState else fromState)
+            val targetValue =
+                propertySpec.transform(
+                    layoutImpl,
+                    scene,
+                    element,
+                    overscrollState,
+                    transition,
+                    idleValue,
+                )
+
+            // Make sure we don't read progress if values are the same and we don't need to
+            // interpolate, so we don't invalidate the phase where this is read.
+            if (targetValue == idleValue) {
+                return targetValue
+            }
+
+            // TODO(b/290184746): Make sure that we don't overflow transformations associated to a
+            // range.
+            val directionSign = if (transition.isUpOrLeft) -1 else 1
+            val overscrollProgress = transition.progress.let { if (it > 1f) it - 1f else it }
+            val progress = directionSign * overscrollProgress
+            val rangeProgress = propertySpec.range?.progress(progress) ?: progress
+
+            // Interpolate between the value at rest and the over scrolled value.
+            return lerp(idleValue, targetValue, rangeProgress)
+        }
+    }
+
     // The element is shared: interpolate between the value in fromScene and the value in toScene.
     // TODO(b/290184746): Support non linear shared paths as well as a way to make sure that shared
     // elements follow the finger direction.
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/GestureHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/GestureHandler.kt
deleted file mode 100644
index 58052cd..0000000
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/GestureHandler.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.android.compose.animation.scene
-
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
-
-interface DraggableHandler {
-    fun onDragStarted(startedPosition: Offset, overSlop: Float, pointersDown: Int = 1)
-    fun onDelta(pixels: Float)
-    fun onDragStopped(velocity: Float)
-}
-
-interface NestedScrollHandler {
-    val connection: NestedScrollConnection
-}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
index 3ff869b..05dd5cc 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
@@ -24,7 +24,6 @@
 import androidx.compose.foundation.gestures.horizontalDrag
 import androidx.compose.foundation.gestures.verticalDrag
 import androidx.compose.runtime.Stable
-import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.input.pointer.PointerEvent
@@ -33,7 +32,6 @@
 import androidx.compose.ui.input.pointer.PointerInputChange
 import androidx.compose.ui.input.pointer.PointerInputScope
 import androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNode
-import androidx.compose.ui.input.pointer.pointerInput
 import androidx.compose.ui.input.pointer.positionChange
 import androidx.compose.ui.input.pointer.util.VelocityTracker
 import androidx.compose.ui.input.pointer.util.addPointerInputChange
@@ -69,9 +67,7 @@
     orientation: Orientation,
     enabled: () -> Boolean,
     startDragImmediately: (startedPosition: Offset) -> Boolean,
-    onDragStarted: (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> Unit,
-    onDragDelta: (delta: Float) -> Unit,
-    onDragStopped: (velocity: Float) -> Unit,
+    onDragStarted: (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> DragController,
 ): Modifier =
     this.then(
         MultiPointerDraggableElement(
@@ -79,8 +75,6 @@
             enabled,
             startDragImmediately,
             onDragStarted,
-            onDragDelta,
-            onDragStopped,
         )
     )
 
@@ -89,9 +83,7 @@
     private val enabled: () -> Boolean,
     private val startDragImmediately: (startedPosition: Offset) -> Boolean,
     private val onDragStarted:
-        (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> Unit,
-    private val onDragDelta: (Float) -> Unit,
-    private val onDragStopped: (velocity: Float) -> Unit,
+        (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> DragController,
 ) : ModifierNodeElement<MultiPointerDraggableNode>() {
     override fun create(): MultiPointerDraggableNode =
         MultiPointerDraggableNode(
@@ -99,8 +91,6 @@
             enabled = enabled,
             startDragImmediately = startDragImmediately,
             onDragStarted = onDragStarted,
-            onDragDelta = onDragDelta,
-            onDragStopped = onDragStopped,
         )
 
     override fun update(node: MultiPointerDraggableNode) {
@@ -108,8 +98,6 @@
         node.enabled = enabled
         node.startDragImmediately = startDragImmediately
         node.onDragStarted = onDragStarted
-        node.onDragDelta = onDragDelta
-        node.onDragStopped = onDragStopped
     }
 }
 
@@ -117,9 +105,8 @@
     orientation: Orientation,
     enabled: () -> Boolean,
     var startDragImmediately: (startedPosition: Offset) -> Boolean,
-    var onDragStarted: (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> Unit,
-    var onDragDelta: (Float) -> Unit,
-    var onDragStopped: (velocity: Float) -> Unit,
+    var onDragStarted:
+        (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> DragController,
 ) :
     PointerInputModifierNode,
     DelegatingNode(),
@@ -176,40 +163,33 @@
             return
         }
 
-        val onDragStart: (Offset, Float, Int) -> Unit = { startedPosition, overSlop, pointersDown ->
-            velocityTracker.resetTracking()
-            onDragStarted(startedPosition, overSlop, pointersDown)
-        }
-
-        val onDragCancel: () -> Unit = { onDragStopped(/* velocity= */ 0f) }
-
-        val onDragEnd: () -> Unit = {
-            val maxFlingVelocity =
-                currentValueOf(LocalViewConfiguration).maximumFlingVelocity.let { max ->
-                    Velocity(max, max)
-                }
-
-            val velocity = velocityTracker.calculateVelocity(maxFlingVelocity)
-            onDragStopped(
-                when (orientation) {
-                    Orientation.Horizontal -> velocity.x
-                    Orientation.Vertical -> velocity.y
-                }
-            )
-        }
-
-        val onDrag: (change: PointerInputChange, dragAmount: Float) -> Unit = { change, amount ->
-            velocityTracker.addPointerInputChange(change)
-            onDragDelta(amount)
-        }
-
         detectDragGestures(
             orientation = orientation,
             startDragImmediately = startDragImmediately,
-            onDragStart = onDragStart,
-            onDragEnd = onDragEnd,
-            onDragCancel = onDragCancel,
-            onDrag = onDrag,
+            onDragStart = { startedPosition, overSlop, pointersDown ->
+                velocityTracker.resetTracking()
+                onDragStarted(startedPosition, overSlop, pointersDown)
+            },
+            onDrag = { controller, change, amount ->
+                velocityTracker.addPointerInputChange(change)
+                controller.onDrag(amount)
+            },
+            onDragEnd = { controller ->
+                val viewConfiguration = currentValueOf(LocalViewConfiguration)
+                val maxVelocity = viewConfiguration.maximumFlingVelocity.let { Velocity(it, it) }
+                val velocity = velocityTracker.calculateVelocity(maxVelocity)
+                controller.onStop(
+                    velocity =
+                        when (orientation) {
+                            Orientation.Horizontal -> velocity.x
+                            Orientation.Vertical -> velocity.y
+                        },
+                    canChangeScene = true,
+                )
+            },
+            onDragCancel = { controller ->
+                controller.onStop(velocity = 0f, canChangeScene = true)
+            },
         )
     }
 }
@@ -225,10 +205,10 @@
 private suspend fun PointerInputScope.detectDragGestures(
     orientation: Orientation,
     startDragImmediately: (startedPosition: Offset) -> Boolean,
-    onDragStart: (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> Unit,
-    onDragEnd: () -> Unit,
-    onDragCancel: () -> Unit,
-    onDrag: (change: PointerInputChange, dragAmount: Float) -> Unit,
+    onDragStart: (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> DragController,
+    onDragEnd: (controller: DragController) -> Unit,
+    onDragCancel: (controller: DragController) -> Unit,
+    onDrag: (controller: DragController, change: PointerInputChange, dragAmount: Float) -> Unit,
 ) {
     awaitEachGesture {
         val initialDown = awaitFirstDown(requireUnconsumed = false, pass = PointerEventPass.Initial)
@@ -282,34 +262,34 @@
                 }
             }
 
-            onDragStart(drag.position, overSlop, pressed.size)
+            val controller = onDragStart(drag.position, overSlop, pressed.size)
 
             val successful: Boolean
             try {
-                onDrag(drag, overSlop)
+                onDrag(controller, drag, overSlop)
 
                 successful =
                     when (orientation) {
                         Orientation.Horizontal ->
                             horizontalDrag(drag.id) {
-                                onDrag(it, it.positionChange().x)
+                                onDrag(controller, it, it.positionChange().x)
                                 it.consume()
                             }
                         Orientation.Vertical ->
                             verticalDrag(drag.id) {
-                                onDrag(it, it.positionChange().y)
+                                onDrag(controller, it, it.positionChange().y)
                                 it.consume()
                             }
                     }
             } catch (t: Throwable) {
-                onDragCancel()
+                onDragCancel(controller)
                 throw t
             }
 
             if (successful) {
-                onDragEnd()
+                onDragEnd(controller)
             } else {
-                onDragCancel()
+                onDragCancel(controller)
             }
         }
     }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
index e78f326..5a2f85a 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
@@ -178,7 +178,7 @@
     topOrLeftBehavior: NestedScrollBehavior,
     bottomOrRightBehavior: NestedScrollBehavior,
 ) =
-    SceneNestedScrollHandler(
+    NestedScrollHandlerImpl(
             layoutImpl = layoutImpl,
             orientation = orientation,
             topOrLeftBehavior = topOrLeftBehavior,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index e1f8a09..b7e2dd1 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -25,6 +25,7 @@
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.unit.Density
@@ -390,40 +391,56 @@
 }
 
 /** The result of performing a [UserAction]. */
-class UserActionResult(
+data class UserActionResult(
     /** The scene we should be transitioning to during the [UserAction]. */
     val toScene: SceneKey,
 
-    /**
-     * The distance the action takes to animate from 0% to 100%.
-     *
-     * If `null`, a default distance will be used that depends on the [UserAction] performed.
-     */
-    val distance: UserActionDistance? = null,
-
     /** The key of the transition that should be used. */
     val transitionKey: TransitionKey? = null,
-) {
-    constructor(
-        toScene: SceneKey,
-        distance: Dp,
-        transitionKey: TransitionKey? = null,
-    ) : this(toScene, FixedDistance(distance), transitionKey)
-}
+)
 
 interface UserActionDistance {
     /**
      * Return the **absolute** distance of the user action given the size of the scene we are
      * animating from and the [orientation].
+     *
+     * Note: This function will be called for each drag event until it returns a value > 0f. This
+     * for instance allows you to return 0f or a negative value until the first layout pass of a
+     * scene, so that you can use the size and position of elements in the scene we are
+     * transitioning to when computing this absolute distance.
      */
-    fun Density.absoluteDistance(fromSceneSize: IntSize, orientation: Orientation): Float
+    fun UserActionDistanceScope.absoluteDistance(
+        fromSceneSize: IntSize,
+        orientation: Orientation
+    ): Float
+}
+
+interface UserActionDistanceScope : Density {
+    /**
+     * Return the *target* size of [this] element in the given [scene], i.e. the size of the element
+     * when idle, or `null` if the element is not composed and measured in that scene (yet).
+     */
+    fun ElementKey.targetSize(scene: SceneKey): IntSize?
+
+    /**
+     * Return the *target* offset of [this] element in the given [scene], i.e. the size of the
+     * element when idle, or `null` if the element is not composed and placed in that scene (yet).
+     */
+    fun ElementKey.targetOffset(scene: SceneKey): Offset?
+
+    /**
+     * Return the *target* size of [this] scene, i.e. the size of the scene when idle, or `null` if
+     * the scene was never composed.
+     */
+    fun SceneKey.targetSize(): IntSize?
 }
 
 /** The user action has a fixed [absoluteDistance]. */
-private class FixedDistance(private val distance: Dp) : UserActionDistance {
-    override fun Density.absoluteDistance(fromSceneSize: IntSize, orientation: Orientation): Float {
-        return distance.toPx()
-    }
+class FixedDistance(private val distance: Dp) : UserActionDistance {
+    override fun UserActionDistanceScope.absoluteDistance(
+        fromSceneSize: IntSize,
+        orientation: Orientation,
+    ): Float = distance.toPx()
 }
 
 /**
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index 08399ff..1670e9c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -25,8 +25,13 @@
 import androidx.compose.runtime.snapshots.SnapshotStateMap
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.ApproachLayoutModifierNode
+import androidx.compose.ui.layout.ApproachMeasureScope
 import androidx.compose.ui.layout.LookaheadScope
-import androidx.compose.ui.layout.intermediateLayout
+import androidx.compose.ui.layout.Measurable
+import androidx.compose.ui.layout.MeasureResult
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.util.fastForEach
@@ -96,33 +101,42 @@
                 ?: mutableMapOf<ValueKey, MutableMap<ElementKey?, SnapshotStateMap<SceneKey, *>>>()
                     .also { _sharedValues = it }
 
-    private val horizontalGestureHandler: SceneGestureHandler
-    private val verticalGestureHandler: SceneGestureHandler
+    // TODO(b/317958526): Lazily allocate scene gesture handlers the first time they are needed.
+    private val horizontalDraggableHandler: DraggableHandlerImpl
+    private val verticalDraggableHandler: DraggableHandlerImpl
+
+    private var _userActionDistanceScope: UserActionDistanceScope? = null
+    internal val userActionDistanceScope: UserActionDistanceScope
+        get() =
+            _userActionDistanceScope
+                ?: UserActionDistanceScopeImpl(layoutImpl = this).also {
+                    _userActionDistanceScope = it
+                }
 
     init {
         updateScenes(builder)
 
-        // SceneGestureHandler must wait for the scenes to be initialized, in order to access the
+        // DraggableHandlerImpl must wait for the scenes to be initialized, in order to access the
         // current scene (required for SwipeTransition).
-        horizontalGestureHandler =
-            SceneGestureHandler(
+        horizontalDraggableHandler =
+            DraggableHandlerImpl(
                 layoutImpl = this,
                 orientation = Orientation.Horizontal,
                 coroutineScope = coroutineScope,
             )
 
-        verticalGestureHandler =
-            SceneGestureHandler(
+        verticalDraggableHandler =
+            DraggableHandlerImpl(
                 layoutImpl = this,
                 orientation = Orientation.Vertical,
                 coroutineScope = coroutineScope,
             )
     }
 
-    internal fun gestureHandler(orientation: Orientation): SceneGestureHandler =
+    internal fun draggableHandler(orientation: Orientation): DraggableHandlerImpl =
         when (orientation) {
-            Orientation.Vertical -> verticalGestureHandler
-            Orientation.Horizontal -> horizontalGestureHandler
+            Orientation.Vertical -> verticalDraggableHandler
+            Orientation.Horizontal -> horizontalDraggableHandler
         }
 
     internal fun scene(key: SceneKey): Scene {
@@ -172,46 +186,15 @@
     }
 
     @Composable
-    @OptIn(ExperimentalComposeUiApi::class)
     internal fun Content(modifier: Modifier) {
         Box(
             modifier
                 // Handle horizontal and vertical swipes on this layout.
                 // Note: order here is important and will give a slight priority to the vertical
                 // swipes.
-                .swipeToScene(horizontalGestureHandler)
-                .swipeToScene(verticalGestureHandler)
-                // Animate the size of this layout.
-                .intermediateLayout { measurable, constraints ->
-                    // Measure content normally.
-                    val placeable = measurable.measure(constraints)
-
-                    val width: Int
-                    val height: Int
-                    val transition = state.currentTransition
-                    if (transition == null) {
-                        width = placeable.width
-                        height = placeable.height
-                    } else {
-                        // Interpolate the size.
-                        val fromSize = scene(transition.fromScene).targetSize
-                        val toSize = scene(transition.toScene).targetSize
-
-                        // Optimization: make sure we don't read state.progress if fromSize ==
-                        // toSize to avoid running this code every frame when the layout size does
-                        // not change.
-                        if (fromSize == toSize) {
-                            width = fromSize.width
-                            height = fromSize.height
-                        } else {
-                            val size = lerp(fromSize, toSize, transition.progress)
-                            width = size.width.coerceAtLeast(0)
-                            height = size.height.coerceAtLeast(0)
-                        }
-                    }
-
-                    layout(width, height) { placeable.place(0, 0) }
-                }
+                .swipeToScene(horizontalDraggableHandler)
+                .swipeToScene(verticalDraggableHandler)
+                .then(LayoutElement(layoutImpl = this))
         ) {
             LookaheadScope {
                 val scenesToCompose =
@@ -254,3 +237,54 @@
         scenes.values.forEach { it.targetSize = size }
     }
 }
+
+private data class LayoutElement(private val layoutImpl: SceneTransitionLayoutImpl) :
+    ModifierNodeElement<LayoutNode>() {
+    override fun create(): LayoutNode = LayoutNode(layoutImpl)
+
+    override fun update(node: LayoutNode) {
+        node.layoutImpl = layoutImpl
+    }
+}
+
+private class LayoutNode(var layoutImpl: SceneTransitionLayoutImpl) :
+    Modifier.Node(), ApproachLayoutModifierNode {
+    override fun isMeasurementApproachComplete(lookaheadSize: IntSize): Boolean {
+        return layoutImpl.state.currentTransition == null
+    }
+
+    @ExperimentalComposeUiApi
+    override fun ApproachMeasureScope.approachMeasure(
+        measurable: Measurable,
+        constraints: Constraints,
+    ): MeasureResult {
+        // Measure content normally.
+        val placeable = measurable.measure(constraints)
+
+        val width: Int
+        val height: Int
+        val transition = layoutImpl.state.currentTransition
+        if (transition == null) {
+            width = placeable.width
+            height = placeable.height
+        } else {
+            // Interpolate the size.
+            val fromSize = layoutImpl.scene(transition.fromScene).targetSize
+            val toSize = layoutImpl.scene(transition.toScene).targetSize
+
+            // Optimization: make sure we don't read state.progress if fromSize ==
+            // toSize to avoid running this code every frame when the layout size does
+            // not change.
+            if (fromSize == toSize) {
+                width = fromSize.width
+                height = fromSize.height
+            } else {
+                val size = lerp(fromSize, toSize, transition.progress)
+                width = size.width.coerceAtLeast(0)
+                height = size.height.coerceAtLeast(0)
+            }
+        }
+
+        return layout(width, height) { placeable.place(0, 0) }
+    }
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 662f33f..0fa19bb 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -16,6 +16,7 @@
 
 package com.android.compose.animation.scene
 
+import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.SideEffect
@@ -221,6 +222,23 @@
                 isTransitioning(from = other, to = scene)
         }
     }
+
+    interface HasOverscrollProperties {
+        /**
+         * The position of the [TransitionState.Transition.toScene].
+         *
+         * Used to understand the direction of the overscroll.
+         */
+        val isUpOrLeft: Boolean
+
+        /**
+         * The relative orientation between [TransitionState.Transition.fromScene] and
+         * [TransitionState.Transition.toScene].
+         *
+         * Used to understand the orientation of the overscroll.
+         */
+        val orientation: Orientation
+    }
 }
 
 internal abstract class BaseSceneTransitionLayoutState(
@@ -237,6 +255,25 @@
      */
     internal var transformationSpec: TransformationSpecImpl = TransformationSpec.Empty
 
+    private var fromOverscrollSpec: OverscrollSpecImpl? = null
+    private var toOverscrollSpec: OverscrollSpecImpl? = null
+
+    /**
+     * @return the overscroll [OverscrollSpecImpl] if it is defined for the current
+     *   [transitionState] and we are currently over scrolling.
+     */
+    internal val currentOverscrollSpec: OverscrollSpecImpl?
+        get() {
+            val transition = currentTransition ?: return null
+            if (transition !is TransitionState.HasOverscrollProperties) return null
+            val progress = transition.progress
+            return when {
+                progress < 0f -> fromOverscrollSpec
+                progress > 1f -> toOverscrollSpec
+                else -> null
+            }
+        }
+
     private val activeTransitionLinks = mutableMapOf<StateLink, LinkedTransition>()
 
     /** Whether we can transition to the given [scene]. */
@@ -266,10 +303,13 @@
         transitionKey: TransitionKey?,
     ) {
         // Compute the [TransformationSpec] when the transition starts.
+        val fromScene = transition.fromScene
+        val toScene = transition.toScene
+        val orientation = (transition as? TransitionState.HasOverscrollProperties)?.orientation
         transformationSpec =
-            transitions
-                .transitionSpec(transition.fromScene, transition.toScene, key = transitionKey)
-                .transformationSpec()
+            transitions.transitionSpec(fromScene, toScene, key = transitionKey).transformationSpec()
+        fromOverscrollSpec = orientation?.let { transitions.overscrollSpec(fromScene, it) }
+        toOverscrollSpec = orientation?.let { transitions.overscrollSpec(toScene, it) }
         cancelActiveTransitionLinks()
         setupTransitionLinks(transition)
         transitionState = transition
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
index b8f9359..2dd41cd 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
@@ -21,6 +21,7 @@
 import androidx.compose.animation.core.SpringSpec
 import androidx.compose.animation.core.snap
 import androidx.compose.animation.core.spring
+import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.util.fastForEach
@@ -41,18 +42,22 @@
 internal constructor(
     internal val defaultSwipeSpec: SpringSpec<Float>,
     internal val transitionSpecs: List<TransitionSpecImpl>,
+    internal val overscrollSpecs: List<OverscrollSpecImpl>,
 ) {
-    private val cache =
+    private val transitionCache =
         mutableMapOf<
             SceneKey, MutableMap<SceneKey, MutableMap<TransitionKey?, TransitionSpecImpl>>
         >()
 
+    private val overscrollCache =
+        mutableMapOf<SceneKey, MutableMap<Orientation, OverscrollSpecImpl?>>()
+
     internal fun transitionSpec(
         from: SceneKey,
         to: SceneKey,
         key: TransitionKey?,
     ): TransitionSpecImpl {
-        return cache
+        return transitionCache
             .getOrPut(from) { mutableMapOf() }
             .getOrPut(to) { mutableMapOf() }
             .getOrPut(key) { findSpec(from, to, key) }
@@ -105,6 +110,28 @@
     private fun defaultTransition(from: SceneKey, to: SceneKey) =
         TransitionSpecImpl(key = null, from, to, TransformationSpec.EmptyProvider)
 
+    internal fun overscrollSpec(scene: SceneKey, orientation: Orientation): OverscrollSpecImpl? =
+        overscrollCache
+            .getOrPut(scene) { mutableMapOf() }
+            .getOrPut(orientation) { overscroll(scene, orientation) { it.scene == scene } }
+
+    private fun overscroll(
+        scene: SceneKey,
+        orientation: Orientation,
+        filter: (OverscrollSpecImpl) -> Boolean,
+    ): OverscrollSpecImpl? {
+        var match: OverscrollSpecImpl? = null
+        overscrollSpecs.fastForEach { spec ->
+            if (spec.orientation == orientation && filter(spec)) {
+                if (match != null) {
+                    error("Found multiple transition specs for transition $scene")
+                }
+                match = spec
+            }
+        }
+        return match
+    }
+
     companion object {
         internal val DefaultSwipeSpec =
             spring(
@@ -112,7 +139,12 @@
                 visibilityThreshold = OffsetVisibilityThreshold,
             )
 
-        val Empty = SceneTransitions(DefaultSwipeSpec, transitionSpecs = emptyList())
+        val Empty =
+            SceneTransitions(
+                defaultSwipeSpec = DefaultSwipeSpec,
+                transitionSpecs = emptyList(),
+                overscrollSpecs = emptyList(),
+            )
     }
 }
 
@@ -139,7 +171,7 @@
      */
     fun reversed(): TransitionSpec
 
-    /*
+    /**
      * The [TransformationSpec] associated to this [TransitionSpec].
      *
      * Note that this is called once every a transition associated to this [TransitionSpec] is
@@ -163,6 +195,14 @@
      */
     val swipeSpec: SpringSpec<Float>?
 
+    /**
+     * The distance it takes for this transition to animate from 0% to 100% when it is driven by a
+     * [UserAction].
+     *
+     * If `null`, a default distance will be used that depends on the [UserAction] performed.
+     */
+    val distance: UserActionDistance?
+
     /** The list of [Transformation] applied to elements during this transition. */
     val transformations: List<Transformation>
 
@@ -171,6 +211,7 @@
             TransformationSpecImpl(
                 progressSpec = snap(),
                 swipeSpec = null,
+                distance = null,
                 transformations = emptyList(),
             )
         internal val EmptyProvider = { Empty }
@@ -193,6 +234,7 @@
                 TransformationSpecImpl(
                     progressSpec = reverse.progressSpec,
                     swipeSpec = reverse.swipeSpec,
+                    distance = reverse.distance,
                     transformations = reverse.transformations.map { it.reversed() }
                 )
             }
@@ -202,6 +244,24 @@
     override fun transformationSpec(): TransformationSpecImpl = this.transformationSpec.invoke()
 }
 
+/** The definition of the overscroll behavior of the [scene]. */
+interface OverscrollSpec {
+    /** The scene we are over scrolling. */
+    val scene: SceneKey
+
+    /** The orientation of this [OverscrollSpec]. */
+    val orientation: Orientation
+
+    /** The [TransformationSpec] associated to this [OverscrollSpec]. */
+    val transformationSpec: TransformationSpec
+}
+
+internal class OverscrollSpecImpl(
+    override val scene: SceneKey,
+    override val orientation: Orientation,
+    override val transformationSpec: TransformationSpecImpl,
+) : OverscrollSpec
+
 /**
  * An implementation of [TransformationSpec] that allows the quick retrieval of an element
  * [ElementTransformations].
@@ -209,6 +269,7 @@
 internal class TransformationSpecImpl(
     override val progressSpec: AnimationSpec<Float>,
     override val swipeSpec: SpringSpec<Float>?,
+    override val distance: UserActionDistance?,
     override val transformations: List<Transformation>,
 ) : TransformationSpec {
     private val cache = mutableMapOf<ElementKey, MutableMap<SceneKey, ElementTransformations>>()
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
index 61f4978..b618369 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -31,39 +31,39 @@
  * Configures the swipeable behavior of a [SceneTransitionLayout] depending on the current state.
  */
 @Stable
-internal fun Modifier.swipeToScene(gestureHandler: SceneGestureHandler): Modifier {
-    return this.then(SwipeToSceneElement(gestureHandler))
+internal fun Modifier.swipeToScene(draggableHandler: DraggableHandlerImpl): Modifier {
+    return this.then(SwipeToSceneElement(draggableHandler))
 }
 
 private data class SwipeToSceneElement(
-    val gestureHandler: SceneGestureHandler,
+    val draggableHandler: DraggableHandlerImpl,
 ) : ModifierNodeElement<SwipeToSceneNode>() {
-    override fun create(): SwipeToSceneNode = SwipeToSceneNode(gestureHandler)
+    override fun create(): SwipeToSceneNode = SwipeToSceneNode(draggableHandler)
 
     override fun update(node: SwipeToSceneNode) {
-        node.gestureHandler = gestureHandler
+        node.draggableHandler = draggableHandler
     }
 }
 
 private class SwipeToSceneNode(
-    gestureHandler: SceneGestureHandler,
+    draggableHandler: DraggableHandlerImpl,
 ) : DelegatingNode(), PointerInputModifierNode {
     private val delegate =
         delegate(
             MultiPointerDraggableNode(
-                orientation = gestureHandler.orientation,
+                orientation = draggableHandler.orientation,
                 enabled = ::enabled,
                 startDragImmediately = ::startDragImmediately,
-                onDragStarted = gestureHandler.draggable::onDragStarted,
-                onDragDelta = gestureHandler.draggable::onDelta,
-                onDragStopped = gestureHandler.draggable::onDragStopped,
+                onDragStarted = draggableHandler::onDragStarted,
             )
         )
 
-    var gestureHandler: SceneGestureHandler = gestureHandler
+    private var _draggableHandler = draggableHandler
+    var draggableHandler: DraggableHandlerImpl
+        get() = _draggableHandler
         set(value) {
-            if (value != field) {
-                field = value
+            if (_draggableHandler != value) {
+                _draggableHandler = value
 
                 // Make sure to update the delegate orientation. Note that this will automatically
                 // reset the underlying pointer input handler, so previous gestures will be
@@ -81,12 +81,12 @@
     override fun onCancelPointerInput() = delegate.onCancelPointerInput()
 
     private fun enabled(): Boolean {
-        return gestureHandler.isDrivingTransition ||
-            currentScene().shouldEnableSwipes(gestureHandler.orientation)
+        return draggableHandler.isDrivingTransition ||
+            currentScene().shouldEnableSwipes(delegate.orientation)
     }
 
     private fun currentScene(): Scene {
-        val layoutImpl = gestureHandler.layoutImpl
+        val layoutImpl = draggableHandler.layoutImpl
         return layoutImpl.scene(layoutImpl.state.transitionState.currentScene)
     }
 
@@ -98,12 +98,12 @@
     private fun startDragImmediately(startedPosition: Offset): Boolean {
         // Immediately start the drag if the user can't swipe in the other direction and the gesture
         // handler can intercept it.
-        return !canOppositeSwipe() && gestureHandler.shouldImmediatelyIntercept(startedPosition)
+        return !canOppositeSwipe() && draggableHandler.shouldImmediatelyIntercept(startedPosition)
     }
 
     private fun canOppositeSwipe(): Boolean {
         val oppositeOrientation =
-            when (gestureHandler.orientation) {
+            when (draggableHandler.orientation) {
                 Orientation.Vertical -> Orientation.Horizontal
                 Orientation.Horizontal -> Orientation.Vertical
             }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
index d93911d..bc52a28 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
@@ -18,6 +18,7 @@
 
 import androidx.compose.animation.core.AnimationSpec
 import androidx.compose.animation.core.SpringSpec
+import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
@@ -72,23 +73,30 @@
         key: TransitionKey? = null,
         builder: TransitionBuilder.() -> Unit = {},
     ): TransitionSpec
+
+    /**
+     * Define the animation to be played when the [scene] is overscrolled in the given
+     * [orientation].
+     *
+     * The overscroll animation always starts from a progress of 0f, and reaches 1f when moving the
+     * [distance] down/right, -1f when moving in the opposite direction.
+     */
+    fun overscroll(
+        scene: SceneKey,
+        orientation: Orientation,
+        builder: OverscrollBuilder.() -> Unit = {},
+    ): OverscrollSpec
 }
 
 @TransitionDsl
-interface TransitionBuilder : PropertyTransformationBuilder {
+interface OverscrollBuilder : PropertyTransformationBuilder {
     /**
-     * The [AnimationSpec] used to animate the associated transition progress from `0` to `1` when
-     * the transition is triggered (i.e. it is not gesture-based).
-     */
-    var spec: AnimationSpec<Float>
-
-    /**
-     * The [SpringSpec] used to animate the associated transition progress when the transition was
-     * started by a swipe and is now animating back to a scene because the user lifted their finger.
+     * The distance it takes for this transition to animate from 0% to 100% when it is driven by a
+     * [UserAction].
      *
-     * If `null`, then the [SceneTransitionsBuilder.defaultSwipeSpec] will be used.
+     * If `null`, a default distance will be used that depends on the [UserAction] performed.
      */
-    var swipeSpec: SpringSpec<Float>?
+    var distance: UserActionDistance?
 
     /**
      * Define a progress-based range for the transformations inside [builder].
@@ -109,6 +117,23 @@
         end: Float? = null,
         builder: PropertyTransformationBuilder.() -> Unit,
     )
+}
+
+@TransitionDsl
+interface TransitionBuilder : OverscrollBuilder, PropertyTransformationBuilder {
+    /**
+     * The [AnimationSpec] used to animate the associated transition progress from `0` to `1` when
+     * the transition is triggered (i.e. it is not gesture-based).
+     */
+    var spec: AnimationSpec<Float>
+
+    /**
+     * The [SpringSpec] used to animate the associated transition progress when the transition was
+     * started by a swipe and is now animating back to a scene because the user lifted their finger.
+     *
+     * If `null`, then the [SceneTransitionsBuilder.defaultSwipeSpec] will be used.
+     */
+    var swipeSpec: SpringSpec<Float>?
 
     /**
      * Define a timestamp-based range for the transformations inside [builder].
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
index 9b16d46..65e8ea5 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
@@ -21,7 +21,9 @@
 import androidx.compose.animation.core.Spring
 import androidx.compose.animation.core.SpringSpec
 import androidx.compose.animation.core.VectorConverter
+import androidx.compose.animation.core.snap
 import androidx.compose.animation.core.spring
+import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.unit.Dp
 import com.android.compose.animation.scene.transformation.AnchoredSize
@@ -41,13 +43,18 @@
     builder: SceneTransitionsBuilder.() -> Unit,
 ): SceneTransitions {
     val impl = SceneTransitionsBuilderImpl().apply(builder)
-    return SceneTransitions(impl.defaultSwipeSpec, impl.transitionSpecs)
+    return SceneTransitions(
+        impl.defaultSwipeSpec,
+        impl.transitionSpecs,
+        impl.transitionOverscrollSpecs
+    )
 }
 
 private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder {
     override var defaultSwipeSpec: SpringSpec<Float> = SceneTransitions.DefaultSwipeSpec
 
     val transitionSpecs = mutableListOf<TransitionSpecImpl>()
+    val transitionOverscrollSpecs = mutableListOf<OverscrollSpecImpl>()
 
     override fun to(
         to: SceneKey,
@@ -66,6 +73,25 @@
         return transition(from = from, to = to, key = key, builder)
     }
 
+    override fun overscroll(
+        scene: SceneKey,
+        orientation: Orientation,
+        builder: OverscrollBuilder.() -> Unit
+    ): OverscrollSpec {
+        fun transformationSpec(): TransformationSpecImpl {
+            val impl = OverscrollBuilderImpl().apply(builder)
+            return TransformationSpecImpl(
+                progressSpec = snap(),
+                swipeSpec = null,
+                distance = impl.distance,
+                transformations = impl.transformations,
+            )
+        }
+        val spec = OverscrollSpecImpl(scene, orientation, transformationSpec())
+        transitionOverscrollSpecs.add(spec)
+        return spec
+    }
+
     private fun transition(
         from: SceneKey?,
         to: SceneKey?,
@@ -77,6 +103,7 @@
             return TransformationSpecImpl(
                 progressSpec = impl.spec,
                 swipeSpec = impl.swipeSpec,
+                distance = impl.distance,
                 transformations = impl.transformations,
             )
         }
@@ -87,27 +114,11 @@
     }
 }
 
-internal class TransitionBuilderImpl : TransitionBuilder {
+internal open class OverscrollBuilderImpl : OverscrollBuilder {
     val transformations = mutableListOf<Transformation>()
-    override var spec: AnimationSpec<Float> = spring(stiffness = Spring.StiffnessLow)
-    override var swipeSpec: SpringSpec<Float>? = null
-
     private var range: TransformationRange? = null
-    private var reversed = false
-    private val durationMillis: Int by lazy {
-        val spec = spec
-        if (spec !is DurationBasedAnimationSpec) {
-            error("timestampRange {} can only be used with a DurationBasedAnimationSpec")
-        }
-
-        spec.vectorize(Float.VectorConverter).durationMillis
-    }
-
-    override fun reversed(builder: TransitionBuilder.() -> Unit) {
-        reversed = true
-        builder()
-        reversed = false
-    }
+    protected var reversed = false
+    override var distance: UserActionDistance? = null
 
     override fun fractionRange(
         start: Float?,
@@ -119,28 +130,6 @@
         range = null
     }
 
-    override fun sharedElement(matcher: ElementMatcher, enabled: Boolean) {
-        transformations.add(SharedElementTransformation(matcher, enabled))
-    }
-
-    override fun timestampRange(
-        startMillis: Int?,
-        endMillis: Int?,
-        builder: PropertyTransformationBuilder.() -> Unit
-    ) {
-        if (startMillis != null && (startMillis < 0 || startMillis > durationMillis)) {
-            error("invalid start value: startMillis=$startMillis durationMillis=$durationMillis")
-        }
-
-        if (endMillis != null && (endMillis < 0 || endMillis > durationMillis)) {
-            error("invalid end value: endMillis=$startMillis durationMillis=$durationMillis")
-        }
-
-        val start = startMillis?.let { it.toFloat() / durationMillis }
-        val end = endMillis?.let { it.toFloat() / durationMillis }
-        fractionRange(start, end, builder)
-    }
-
     private fun transformation(transformation: PropertyTransformation<*>) {
         val transformation =
             if (range != null) {
@@ -195,3 +184,45 @@
         transformation(AnchoredSize(matcher, anchor, anchorWidth, anchorHeight))
     }
 }
+
+internal class TransitionBuilderImpl : OverscrollBuilderImpl(), TransitionBuilder {
+    override var spec: AnimationSpec<Float> = spring(stiffness = Spring.StiffnessLow)
+    override var swipeSpec: SpringSpec<Float>? = null
+    override var distance: UserActionDistance? = null
+    private val durationMillis: Int by lazy {
+        val spec = spec
+        if (spec !is DurationBasedAnimationSpec) {
+            error("timestampRange {} can only be used with a DurationBasedAnimationSpec")
+        }
+
+        spec.vectorize(Float.VectorConverter).durationMillis
+    }
+
+    override fun reversed(builder: TransitionBuilder.() -> Unit) {
+        reversed = true
+        builder()
+        reversed = false
+    }
+
+    override fun sharedElement(matcher: ElementMatcher, enabled: Boolean) {
+        transformations.add(SharedElementTransformation(matcher, enabled))
+    }
+
+    override fun timestampRange(
+        startMillis: Int?,
+        endMillis: Int?,
+        builder: PropertyTransformationBuilder.() -> Unit
+    ) {
+        if (startMillis != null && (startMillis < 0 || startMillis > durationMillis)) {
+            error("invalid start value: startMillis=$startMillis durationMillis=$durationMillis")
+        }
+
+        if (endMillis != null && (endMillis < 0 || endMillis > durationMillis)) {
+            error("invalid end value: endMillis=$startMillis durationMillis=$durationMillis")
+        }
+
+        val start = startMillis?.let { it.toFloat() / durationMillis }
+        val end = endMillis?.let { it.toFloat() / durationMillis }
+        fractionRange(start, end, builder)
+    }
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt
new file mode 100644
index 0000000..228d19f
--- /dev/null
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene
+
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.unit.IntSize
+
+internal class UserActionDistanceScopeImpl(
+    private val layoutImpl: SceneTransitionLayoutImpl,
+) : UserActionDistanceScope {
+    override val density: Float
+        get() = layoutImpl.density.density
+
+    override val fontScale: Float
+        get() = layoutImpl.density.fontScale
+
+    override fun ElementKey.targetSize(scene: SceneKey): IntSize? {
+        return layoutImpl.elements[this]?.sceneStates?.get(scene)?.targetSize.takeIf {
+            it != Element.SizeUnspecified
+        }
+    }
+
+    override fun ElementKey.targetOffset(scene: SceneKey): Offset? {
+        return layoutImpl.elements[this]?.sceneStates?.get(scene)?.targetOffset.takeIf {
+            it != Offset.Unspecified
+        }
+    }
+
+    override fun SceneKey.targetSize(): IntSize? {
+        return layoutImpl.scenes[this]?.targetSize.takeIf { it != IntSize.Zero }
+    }
+}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
similarity index 81%
rename from packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
rename to packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
index fe53d5b..eb9b428 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
@@ -47,12 +47,12 @@
 private val LAYOUT_SIZE = IntSize(SCREEN_SIZE.toInt(), SCREEN_SIZE.toInt())
 
 @RunWith(AndroidJUnit4::class)
-class SceneGestureHandlerTest {
+class DraggableHandlerTest {
     private class TestGestureScope(
         private val testScope: MonotonicClockTestScope,
     ) {
         var canChangeScene: (SceneKey) -> Boolean = { true }
-        private val layoutState =
+        val layoutState =
             MutableSceneTransitionLayoutStateImpl(
                 SceneA,
                 EmptyTestTransitions,
@@ -99,19 +99,19 @@
                 )
                 .apply { setScenesTargetSizeForTest(LAYOUT_SIZE) }
 
-        val sceneGestureHandler = layoutImpl.gestureHandler(Orientation.Vertical)
-        val horizontalSceneGestureHandler = layoutImpl.gestureHandler(Orientation.Horizontal)
+        val draggableHandler = layoutImpl.draggableHandler(Orientation.Vertical)
+        val horizontalDraggableHandler = layoutImpl.draggableHandler(Orientation.Horizontal)
 
         fun nestedScrollConnection(nestedScrollBehavior: NestedScrollBehavior) =
-            SceneNestedScrollHandler(
+            NestedScrollHandlerImpl(
                     layoutImpl = layoutImpl,
-                    orientation = sceneGestureHandler.orientation,
+                    orientation = draggableHandler.orientation,
                     topOrLeftBehavior = nestedScrollBehavior,
                     bottomOrRightBehavior = nestedScrollBehavior,
                 )
                 .connection
 
-        val velocityThreshold = sceneGestureHandler.velocityThreshold
+        val velocityThreshold = draggableHandler.velocityThreshold
 
         fun down(fractionOfScreen: Float) =
             if (fractionOfScreen < 0f) error("use up()") else SCREEN_SIZE * fractionOfScreen
@@ -190,20 +190,18 @@
         fun onDragStarted(
             startedPosition: Offset = Offset.Zero,
             overSlop: Float,
-            pointersDown: Int = 1
-        ) {
+            pointersDown: Int = 1,
+        ): DragController {
             // overSlop should be 0f only if the drag gesture starts with startDragImmediately
             if (overSlop == 0f) error("Consider using onDragStartedImmediately()")
-            onDragStarted(sceneGestureHandler.draggable, startedPosition, overSlop, pointersDown)
+            return onDragStarted(draggableHandler, startedPosition, overSlop, pointersDown)
         }
 
-        fun onDragStartedImmediately(startedPosition: Offset = Offset.Zero, pointersDown: Int = 1) {
-            onDragStarted(
-                sceneGestureHandler.draggable,
-                startedPosition,
-                overSlop = 0f,
-                pointersDown
-            )
+        fun onDragStartedImmediately(
+            startedPosition: Offset = Offset.Zero,
+            pointersDown: Int = 1,
+        ): DragController {
+            return onDragStarted(draggableHandler, startedPosition, overSlop = 0f, pointersDown)
         }
 
         fun onDragStarted(
@@ -211,24 +209,26 @@
             startedPosition: Offset = Offset.Zero,
             overSlop: Float = 0f,
             pointersDown: Int = 1
-        ) {
-            draggableHandler.onDragStarted(
-                startedPosition = startedPosition,
-                overSlop = overSlop,
-                pointersDown = pointersDown,
-            )
+        ): DragController {
+            val dragController =
+                draggableHandler.onDragStarted(
+                    startedPosition = startedPosition,
+                    overSlop = overSlop,
+                    pointersDown = pointersDown,
+                )
 
             // MultiPointerDraggable will always call onDelta with the initial overSlop right after
-            onDelta(pixels = overSlop)
+            dragController.onDragDelta(pixels = overSlop)
+
+            return dragController
         }
 
-        fun onDelta(pixels: Float) {
-            sceneGestureHandler.draggable.onDelta(pixels = pixels)
+        fun DragController.onDragDelta(pixels: Float) {
+            onDrag(delta = pixels)
         }
 
-        fun onDragStopped(velocity: Float) {
-            sceneGestureHandler.draggable.onDragStopped(velocity = velocity)
-            runCurrent()
+        fun DragController.onDragStopped(velocity: Float, canChangeScene: Boolean = true) {
+            onStop(velocity, canChangeScene)
         }
 
         fun NestedScrollConnection.scroll(
@@ -281,20 +281,20 @@
 
     @Test
     fun afterSceneTransitionIsStarted_interceptDragEvents() = runGestureTest {
-        onDragStarted(overSlop = down(fractionOfScreen = 0.1f))
+        val dragController = onDragStarted(overSlop = down(fractionOfScreen = 0.1f))
         assertTransition(currentScene = SceneA)
         assertThat(progress).isEqualTo(0.1f)
 
-        onDelta(pixels = down(fractionOfScreen = 0.1f))
+        dragController.onDragDelta(pixels = down(fractionOfScreen = 0.1f))
         assertThat(progress).isEqualTo(0.2f)
     }
 
     @Test
     fun onDragStoppedAfterDrag_velocityLowerThanThreshold_remainSameScene() = runGestureTest {
-        onDragStarted(overSlop = down(fractionOfScreen = 0.1f))
+        val dragController = onDragStarted(overSlop = down(fractionOfScreen = 0.1f))
         assertTransition(currentScene = SceneA)
 
-        onDragStopped(velocity = velocityThreshold - 0.01f)
+        dragController.onDragStopped(velocity = velocityThreshold - 0.01f)
         assertTransition(currentScene = SceneA)
 
         // wait for the stop animation
@@ -304,10 +304,10 @@
 
     @Test
     fun onDragStoppedAfterDrag_velocityAtLeastThreshold_goToNextScene() = runGestureTest {
-        onDragStarted(overSlop = down(fractionOfScreen = 0.1f))
+        val dragController = onDragStarted(overSlop = down(fractionOfScreen = 0.1f))
         assertTransition(currentScene = SceneA)
 
-        onDragStopped(velocity = velocityThreshold)
+        dragController.onDragStopped(velocity = velocityThreshold)
         assertTransition(currentScene = SceneC)
 
         // wait for the stop animation
@@ -317,10 +317,10 @@
 
     @Test
     fun onDragStoppedAfterStarted_returnToIdle() = runGestureTest {
-        onDragStarted(overSlop = down(fractionOfScreen = 0.1f))
+        val dragController = onDragStarted(overSlop = down(fractionOfScreen = 0.1f))
         assertTransition(currentScene = SceneA)
 
-        onDragStopped(velocity = 0f)
+        dragController.onDragStopped(velocity = 0f)
         advanceUntilIdle()
         assertIdle(currentScene = SceneA)
     }
@@ -328,7 +328,7 @@
     @Test
     fun onDragReversedDirection_changeToScene() = runGestureTest {
         // Drag A -> B with progress 0.6
-        onDragStarted(overSlop = -60f)
+        val dragController = onDragStarted(overSlop = -60f)
         assertTransition(
             currentScene = SceneA,
             fromScene = SceneA,
@@ -337,7 +337,7 @@
         )
 
         // Reverse direction such that A -> C now with 0.4
-        onDelta(pixels = 100f)
+        dragController.onDragDelta(pixels = 100f)
         assertTransition(
             currentScene = SceneA,
             fromScene = SceneA,
@@ -346,7 +346,7 @@
         )
 
         // After the drag stopped scene C should be committed
-        onDragStopped(velocity = velocityThreshold)
+        dragController.onDragStopped(velocity = velocityThreshold)
         assertTransition(currentScene = SceneC, fromScene = SceneA, toScene = SceneC)
 
         // wait for the stop animation
@@ -356,8 +356,6 @@
 
     @Test
     fun onDragStartedWithoutActionsInBothDirections_stayIdle() = runGestureTest {
-        val horizontalDraggableHandler = horizontalSceneGestureHandler.draggable
-
         onDragStarted(horizontalDraggableHandler, overSlop = up(fractionOfScreen = 0.3f))
         assertIdle(currentScene = SceneA)
 
@@ -370,7 +368,7 @@
         navigateToSceneC()
 
         // We are on SceneC which has no action in Down direction
-        onDragStarted(overSlop = 10f)
+        val dragController = onDragStarted(overSlop = 10f)
         assertTransition(
             currentScene = SceneC,
             fromScene = SceneC,
@@ -379,7 +377,7 @@
         )
 
         // Reverse drag direction, it will consume the previous drag
-        onDelta(pixels = -10f)
+        dragController.onDragDelta(pixels = -10f)
         assertTransition(
             currentScene = SceneC,
             fromScene = SceneC,
@@ -388,7 +386,7 @@
         )
 
         // Continue reverse drag direction, it should record progress to Scene B
-        onDelta(pixels = -10f)
+        dragController.onDragDelta(pixels = -10f)
         assertTransition(
             currentScene = SceneC,
             fromScene = SceneC,
@@ -416,14 +414,14 @@
 
     @Test
     fun onDragToExactlyZero_toSceneIsSet() = runGestureTest {
-        onDragStarted(overSlop = down(fractionOfScreen = 0.3f))
+        val dragController = onDragStarted(overSlop = down(fractionOfScreen = 0.3f))
         assertTransition(
             currentScene = SceneA,
             fromScene = SceneA,
             toScene = SceneC,
             progress = 0.3f
         )
-        onDelta(pixels = up(fractionOfScreen = 0.3f))
+        dragController.onDragDelta(pixels = up(fractionOfScreen = 0.3f))
         assertTransition(
             currentScene = SceneA,
             fromScene = SceneA,
@@ -434,8 +432,8 @@
 
     private fun TestGestureScope.navigateToSceneC() {
         assertIdle(currentScene = SceneA)
-        onDragStarted(overSlop = down(fractionOfScreen = 1f))
-        onDragStopped(velocity = 0f)
+        val dragController = onDragStarted(overSlop = down(fractionOfScreen = 1f))
+        dragController.onDragStopped(velocity = 0f)
         advanceUntilIdle()
         assertIdle(currentScene = SceneC)
     }
@@ -443,7 +441,7 @@
     @Test
     fun onAccelaratedScroll_scrollToThirdScene() = runGestureTest {
         // Drag A -> B with progress 0.2
-        onDragStarted(overSlop = up(fractionOfScreen = 0.2f))
+        val dragController1 = onDragStarted(overSlop = up(fractionOfScreen = 0.2f))
         assertTransition(
             currentScene = SceneA,
             fromScene = SceneA,
@@ -452,13 +450,13 @@
         )
 
         // Start animation A -> B with progress 0.2 -> 1.0
-        onDragStopped(velocity = -velocityThreshold)
+        dragController1.onDragStopped(velocity = -velocityThreshold)
         assertTransition(currentScene = SceneB, fromScene = SceneA, toScene = SceneB)
 
         // While at A -> B do a 100% screen drag (progress 1.2). This should go past B and change
         // the transition to B -> C with progress 0.2
-        onDragStartedImmediately()
-        onDelta(pixels = up(fractionOfScreen = 1f))
+        val dragController2 = onDragStartedImmediately()
+        dragController2.onDragDelta(pixels = up(fractionOfScreen = 1f))
         assertTransition(
             currentScene = SceneB,
             fromScene = SceneB,
@@ -467,7 +465,7 @@
         )
 
         // After the drag stopped scene C should be committed
-        onDragStopped(velocity = -velocityThreshold)
+        dragController2.onDragStopped(velocity = -velocityThreshold)
         assertTransition(currentScene = SceneC, fromScene = SceneB, toScene = SceneC)
 
         // wait for the stop animation
@@ -477,9 +475,9 @@
 
     @Test
     fun onAccelaratedScrollBothTargetsBecomeNull_settlesToIdle() = runGestureTest {
-        onDragStarted(overSlop = up(fractionOfScreen = 0.2f))
-        onDelta(pixels = up(fractionOfScreen = 0.2f))
-        onDragStopped(velocity = -velocityThreshold)
+        val dragController1 = onDragStarted(overSlop = up(fractionOfScreen = 0.2f))
+        dragController1.onDragDelta(pixels = up(fractionOfScreen = 0.2f))
+        dragController1.onDragStopped(velocity = -velocityThreshold)
         assertTransition(currentScene = SceneB, fromScene = SceneA, toScene = SceneB)
 
         mutableUserActionsA.remove(Swipe.Up)
@@ -488,34 +486,34 @@
         mutableUserActionsB.remove(Swipe.Down)
 
         // start accelaratedScroll and scroll over to B -> null
-        onDragStartedImmediately()
-        onDelta(pixels = up(fractionOfScreen = 0.5f))
-        onDelta(pixels = up(fractionOfScreen = 0.5f))
+        val dragController2 = onDragStartedImmediately()
+        dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f))
+        dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f))
 
         // here onDragStopped is already triggered, but subsequent onDelta/onDragStopped calls may
         // still be called. Make sure that they don't crash or change the scene
-        onDelta(pixels = up(fractionOfScreen = 0.5f))
-        onDragStopped(velocity = 0f)
+        dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f))
+        dragController2.onDragStopped(velocity = 0f)
 
         advanceUntilIdle()
         assertIdle(SceneB)
 
         // These events can still come in after the animation has settled
-        onDelta(pixels = up(fractionOfScreen = 0.5f))
-        onDragStopped(velocity = 0f)
+        dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f))
+        dragController2.onDragStopped(velocity = 0f)
         assertIdle(SceneB)
     }
 
     @Test
     fun onDragTargetsChanged_targetStaysTheSame() = runGestureTest {
-        onDragStarted(overSlop = up(fractionOfScreen = 0.1f))
+        val dragController1 = onDragStarted(overSlop = up(fractionOfScreen = 0.1f))
         assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.1f)
 
         mutableUserActionsA[Swipe.Up] = UserActionResult(SceneC)
-        onDelta(pixels = up(fractionOfScreen = 0.1f))
+        dragController1.onDragDelta(pixels = up(fractionOfScreen = 0.1f))
         // target stays B even though UserActions changed
         assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.2f)
-        onDragStopped(velocity = down(fractionOfScreen = 0.1f))
+        dragController1.onDragStopped(velocity = down(fractionOfScreen = 0.1f))
         advanceUntilIdle()
 
         // now target changed to C for new drag
@@ -525,25 +523,26 @@
 
     @Test
     fun onDragTargetsChanged_targetsChangeWhenStartingNewDrag() = runGestureTest {
-        onDragStarted(overSlop = up(fractionOfScreen = 0.1f))
+        val dragController1 = onDragStarted(overSlop = up(fractionOfScreen = 0.1f))
         assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.1f)
 
         mutableUserActionsA[Swipe.Up] = UserActionResult(SceneC)
-        onDelta(pixels = up(fractionOfScreen = 0.1f))
-        onDragStopped(velocity = down(fractionOfScreen = 0.1f))
+        dragController1.onDragDelta(pixels = up(fractionOfScreen = 0.1f))
+        dragController1.onDragStopped(velocity = down(fractionOfScreen = 0.1f))
 
         // now target changed to C for new drag that started before previous drag settled to Idle
-        onDragStartedImmediately()
-        onDelta(pixels = up(fractionOfScreen = 0.1f))
+        val dragController2 = onDragStartedImmediately()
+        dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.1f))
         assertTransition(fromScene = SceneA, toScene = SceneC, progress = 0.3f)
     }
 
     @Test
     fun startGestureDuringAnimatingOffset_shouldImmediatelyStopTheAnimation() = runGestureTest {
-        onDragStarted(overSlop = down(fractionOfScreen = 0.1f))
+        val dragController = onDragStarted(overSlop = down(fractionOfScreen = 0.1f))
         assertTransition(currentScene = SceneA)
 
-        onDragStopped(velocity = velocityThreshold)
+        dragController.onDragStopped(velocity = velocityThreshold)
+        runCurrent()
 
         assertTransition(currentScene = SceneC)
         assertThat(isUserInputOngoing).isFalse()
@@ -632,7 +631,7 @@
         // stop scene transition (start the "stop animation")
         nestedScroll.preFling(available = Velocity.Zero)
 
-        // a pre scroll event, that could be intercepted by SceneGestureHandler
+        // a pre scroll event, that could be intercepted by DraggableHandlerImpl
         nestedScroll.onPreScroll(
             available = Offset(0f, secondScroll),
             source = NestedScrollSource.Drag
@@ -801,18 +800,6 @@
     }
 
     @Test
-    fun beforeDraggableStart_drag_shouldBeIgnored() = runGestureTest {
-        onDelta(pixels = down(fractionOfScreen = 0.1f))
-        assertIdle(currentScene = SceneA)
-    }
-
-    @Test
-    fun beforeDraggableStart_stop_shouldBeIgnored() = runGestureTest {
-        onDragStopped(velocity = velocityThreshold)
-        assertIdle(currentScene = SceneA)
-    }
-
-    @Test
     fun beforeNestedScrollStart_stop_shouldBeIgnored() = runGestureTest {
         val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeWithPreview)
         nestedScroll.preFling(available = Velocity(0f, velocityThreshold))
@@ -826,7 +813,7 @@
         val offsetY10 = downOffset(fractionOfScreen = 0.1f)
 
         // Start a drag and then stop it, given that
-        onDragStarted(overSlop = up(0.1f))
+        val dragController = onDragStarted(overSlop = up(0.1f))
 
         assertTransition(currentScene = SceneA)
         assertThat(progress).isEqualTo(0.1f)
@@ -836,7 +823,7 @@
         assertThat(progress).isEqualTo(0.2f)
 
         // this should be ignored, we are scrolling now!
-        onDragStopped(-velocityThreshold)
+        dragController.onDragStopped(-velocityThreshold)
         assertTransition(currentScene = SceneA)
 
         nestedScroll.scroll(available = -offsetY10)
@@ -865,6 +852,7 @@
             currentScene = SceneC,
             fromScene = SceneC,
             toScene = SceneB,
+            progress = 0.1f,
             isUserInputOngoing = true,
         )
 
@@ -873,18 +861,25 @@
         // During the current gesture, start a new gesture, still in the middle of the screen. We
         // should intercept it. Because it is intercepted, the overSlop passed to onDragStarted()
         // should be 0f.
-        assertThat(sceneGestureHandler.shouldImmediatelyIntercept(middle)).isTrue()
+        assertThat(draggableHandler.shouldImmediatelyIntercept(middle)).isTrue()
         onDragStartedImmediately(startedPosition = middle)
 
         // We should have intercepted the transition, so the transition should be the same object.
-        assertTransition(currentScene = SceneC, fromScene = SceneC, toScene = SceneB)
-        assertThat(transitionState).isSameInstanceAs(firstTransition)
+        assertTransition(
+            currentScene = SceneC,
+            fromScene = SceneC,
+            toScene = SceneB,
+            progress = 0.1f,
+            isUserInputOngoing = true,
+        )
+        // We should have a new transition
+        assertThat(transitionState).isNotSameInstanceAs(firstTransition)
 
         // Start a new gesture from the bottom of the screen. Because swiping up from the bottom of
         // C leads to scene A (and not B), the previous transitions is *not* intercepted and we
         // instead animate from C to A.
         val bottom = Offset(SCREEN_SIZE / 2, SCREEN_SIZE)
-        assertThat(sceneGestureHandler.shouldImmediatelyIntercept(bottom)).isFalse()
+        assertThat(draggableHandler.shouldImmediatelyIntercept(bottom)).isFalse()
         onDragStarted(startedPosition = bottom, overSlop = up(0.1f))
 
         assertTransition(
@@ -901,12 +896,12 @@
         assertIdle(SceneA)
 
         // Swipe up to scene B.
-        onDragStarted(overSlop = up(0.1f))
+        val dragController = onDragStarted(overSlop = up(0.1f))
         assertTransition(currentScene = SceneA, fromScene = SceneA, toScene = SceneB)
 
         // Block the transition when the user release their finger.
         canChangeScene = { false }
-        onDragStopped(velocity = -velocityThreshold)
+        dragController.onDragStopped(velocity = -velocityThreshold)
         advanceUntilIdle()
         assertIdle(SceneA)
     }
@@ -916,20 +911,44 @@
         assertIdle(SceneA)
 
         // Swipe up to B.
-        onDragStarted(overSlop = up(0.1f))
+        val dragController1 = onDragStarted(overSlop = up(0.1f))
         assertTransition(currentScene = SceneA, fromScene = SceneA, toScene = SceneB)
-        onDragStopped(velocity = -velocityThreshold)
+        dragController1.onDragStopped(velocity = -velocityThreshold)
         assertTransition(currentScene = SceneB, fromScene = SceneA, toScene = SceneB)
 
         // Intercept the transition and swipe down back to scene A.
-        assertThat(sceneGestureHandler.shouldImmediatelyIntercept(startedPosition = null)).isTrue()
-        onDragStartedImmediately()
+        assertThat(draggableHandler.shouldImmediatelyIntercept(startedPosition = null)).isTrue()
+        val dragController2 = onDragStartedImmediately()
 
         // Block the transition when the user release their finger.
         canChangeScene = { false }
-        onDragStopped(velocity = velocityThreshold)
+        dragController2.onDragStopped(velocity = velocityThreshold)
 
         advanceUntilIdle()
         assertIdle(SceneB)
     }
+
+    @Test
+    fun scrollFromIdleWithNoTargetScene_shouldUseOverscrollSpecIfAvailable() = runGestureTest {
+        layoutState.transitions = transitions {
+            overscroll(SceneC, Orientation.Vertical) { fade(TestElements.Foo) }
+        }
+        // Start at scene C.
+        navigateToSceneC()
+
+        val scene = layoutState.transitionState.currentScene
+        // We should have overscroll spec for scene C
+        assertThat(layoutState.transitions.overscrollSpec(scene, Orientation.Vertical)).isNotNull()
+        assertThat(layoutState.currentOverscrollSpec).isNull()
+
+        val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeAlways)
+        nestedScroll.scroll(available = downOffset(fractionOfScreen = 0.1f))
+
+        // We scrolled down, under scene C there is nothing, so we can use the overscroll spec
+        assertThat(layoutState.currentOverscrollSpec).isNotNull()
+        assertThat(layoutState.currentOverscrollSpec?.scene).isEqualTo(SceneC)
+        val transition = layoutState.currentTransition
+        assertThat(transition).isNotNull()
+        assertThat(transition!!.progress).isEqualTo(-0.1f)
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index 33be1dc..059a10e 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -18,9 +18,13 @@
 
 import androidx.compose.animation.core.tween
 import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.rememberScrollableState
+import androidx.compose.foundation.gestures.scrollable
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.size
@@ -34,8 +38,14 @@
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.layout.intermediateLayout
+import androidx.compose.ui.platform.LocalViewConfiguration
+import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
 import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.test.performTouchInput
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -528,4 +538,157 @@
             after { assertThat(fooCompositions).isEqualTo(1) }
         }
     }
+
+    @Test
+    fun elementTransitionDuringOverscroll() {
+        // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is
+        // detected as a drag event.
+        var touchSlop = 0f
+        val overscrollTranslateY = 10.dp
+        val layoutWidth = 200.dp
+        val layoutHeight = 400.dp
+
+        val state =
+            MutableSceneTransitionLayoutState(
+                initialScene = TestScenes.SceneA,
+                transitions =
+                    transitions {
+                        overscroll(TestScenes.SceneB, Orientation.Vertical) {
+                            translate(TestElements.Foo, y = overscrollTranslateY)
+                        }
+                    }
+            )
+                as MutableSceneTransitionLayoutStateImpl
+
+        rule.setContent {
+            touchSlop = LocalViewConfiguration.current.touchSlop
+            SceneTransitionLayout(
+                state = state,
+                modifier = Modifier.size(layoutWidth, layoutHeight)
+            ) {
+                scene(
+                    key = TestScenes.SceneA,
+                    userActions = mapOf(Swipe.Down to TestScenes.SceneB)
+                ) {
+                    Spacer(Modifier.fillMaxSize())
+                }
+                scene(TestScenes.SceneB) {
+                    Spacer(Modifier.element(TestElements.Foo).fillMaxSize())
+                }
+            }
+        }
+
+        assertThat(state.currentTransition).isNull()
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // Swipe by half of verticalSwipeDistance.
+        rule.onRoot().performTouchInput {
+            val middleTop = Offset((layoutWidth / 2).toPx(), 0f)
+            down(middleTop)
+            // Scroll 50%
+            moveBy(Offset(0f, touchSlop + layoutHeight.toPx() * 0.5f), delayMillis = 1_000)
+        }
+
+        val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag, useUnmergedTree = true)
+        fooElement.assertTopPositionInRootIsEqualTo(0.dp)
+        val transition = state.currentTransition
+        assertThat(transition).isNotNull()
+        assertThat(transition!!.progress).isEqualTo(0.5f)
+
+        rule.onRoot().performTouchInput {
+            // Scroll another 100%
+            moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000)
+        }
+
+        // Scroll 150% (Scene B overscroll by 50%)
+        assertThat(transition.progress).isEqualTo(1.5f)
+        assertThat(state.currentOverscrollSpec).isNotNull()
+        fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 0.5f)
+
+        rule.onRoot().performTouchInput {
+            // Scroll another 100%
+            moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000)
+        }
+
+        // Scroll 250% (Scene B overscroll by 150%)
+        assertThat(transition.progress).isEqualTo(2.5f)
+        assertThat(state.currentOverscrollSpec).isNotNull()
+        fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 1.5f)
+    }
+
+    @Test
+    fun elementTransitionDuringNestedScrollOverscroll() {
+        // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is
+        // detected as a drag event.
+        var touchSlop = 0f
+        val overscrollTranslateY = 10.dp
+        val layoutWidth = 200.dp
+        val layoutHeight = 400.dp
+
+        val state =
+            MutableSceneTransitionLayoutState(
+                initialScene = TestScenes.SceneB,
+                transitions =
+                    transitions {
+                        overscroll(TestScenes.SceneB, Orientation.Vertical) {
+                            translate(TestElements.Foo, y = overscrollTranslateY)
+                        }
+                    }
+            )
+                as MutableSceneTransitionLayoutStateImpl
+
+        rule.setContent {
+            touchSlop = LocalViewConfiguration.current.touchSlop
+            SceneTransitionLayout(
+                state = state,
+                modifier = Modifier.size(layoutWidth, layoutHeight)
+            ) {
+                scene(TestScenes.SceneA) { Spacer(Modifier.fillMaxSize()) }
+                scene(TestScenes.SceneB, userActions = mapOf(Swipe.Up to TestScenes.SceneA)) {
+                    Box(
+                        Modifier
+                            // Unconsumed scroll gesture will be intercepted by STL
+                            .verticalNestedScrollToScene()
+                            // A scrollable that does not consume the scroll gesture
+                            .scrollable(
+                                rememberScrollableState(consumeScrollDelta = { 0f }),
+                                Orientation.Vertical
+                            )
+                            .fillMaxSize()
+                    ) {
+                        Spacer(Modifier.element(TestElements.Foo).fillMaxSize())
+                    }
+                }
+            }
+        }
+
+        assertThat(state.currentTransition).isNull()
+        assertThat(state.currentOverscrollSpec).isNull()
+        val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag, useUnmergedTree = true)
+        fooElement.assertTopPositionInRootIsEqualTo(0.dp)
+
+        // Swipe by half of verticalSwipeDistance.
+        rule.onRoot().performTouchInput {
+            val middleTop = Offset((layoutWidth / 2).toPx(), 0f)
+            down(middleTop)
+            // Scroll 50%
+            moveBy(Offset(0f, touchSlop + layoutHeight.toPx() * 0.5f), delayMillis = 1_000)
+        }
+
+        val transition = state.currentTransition
+        assertThat(state.currentOverscrollSpec).isNotNull()
+        assertThat(transition).isNotNull()
+        assertThat(transition!!.progress).isEqualTo(-0.5f)
+        fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 0.5f)
+
+        rule.onRoot().performTouchInput {
+            // Scroll another 100%
+            moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000)
+        }
+
+        // Scroll 150% (Scene B overscroll by 50%)
+        assertThat(transition.progress).isEqualTo(-1.5f)
+        assertThat(state.currentOverscrollSpec).isNotNull()
+        fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 1.5f)
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
index cd99d05..d8cf1c1 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
@@ -59,9 +59,18 @@
                         orientation = Orientation.Vertical,
                         enabled = { enabled },
                         startDragImmediately = { false },
-                        onDragStarted = { _, _, _ -> started = true },
-                        onDragDelta = { _ -> dragged = true },
-                        onDragStopped = { stopped = true },
+                        onDragStarted = { _, _, _ ->
+                            started = true
+                            object : DragController {
+                                override fun onDrag(delta: Float) {
+                                    dragged = true
+                                }
+
+                                override fun onStop(velocity: Float, canChangeScene: Boolean) {
+                                    stopped = true
+                                }
+                            }
+                        },
                     )
             )
         }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
index f81a7f2..3cbcd73 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
@@ -16,6 +16,8 @@
 
 package com.android.compose.animation.scene
 
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.runtime.mutableStateOf
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.compose.animation.scene.TestScenes.SceneA
@@ -389,4 +391,118 @@
         assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue()
         assertThat(parentState.isTransitioning(SceneC, SceneD)).isFalse()
     }
+
+    private fun startOverscrollableTransistionFromAtoB(
+        progress: () -> Float,
+        sceneTransitions: SceneTransitions,
+    ): MutableSceneTransitionLayoutStateImpl {
+        val state =
+            MutableSceneTransitionLayoutStateImpl(
+                SceneA,
+                sceneTransitions,
+            )
+        state.startTransition(
+            object :
+                TransitionState.Transition(SceneA, SceneB),
+                TransitionState.HasOverscrollProperties {
+                override val currentScene: SceneKey = SceneA
+                override val progress: Float
+                    get() = progress()
+
+                override val isInitiatedByUserInput: Boolean = false
+                override val isUserInputOngoing: Boolean = false
+                override val isUpOrLeft: Boolean = false
+                override val orientation: Orientation = Orientation.Vertical
+            },
+            transitionKey = null
+        )
+        assertThat(state.isTransitioning()).isTrue()
+        return state
+    }
+
+    @Test
+    fun overscrollDsl_definedForToScene() = runMonotonicClockTest {
+        val progress = mutableStateOf(0f)
+        val state =
+            startOverscrollableTransistionFromAtoB(
+                progress = { progress.value },
+                sceneTransitions =
+                    transitions {
+                        overscroll(SceneB, Orientation.Vertical) { fade(TestElements.Foo) }
+                    }
+            )
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // overscroll for SceneA is NOT defined
+        progress.value = -0.1f
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // scroll from SceneA to SceneB
+        progress.value = 0.5f
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        progress.value = 1f
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // overscroll for SceneB is defined
+        progress.value = 1.1f
+        assertThat(state.currentOverscrollSpec).isNotNull()
+        assertThat(state.currentOverscrollSpec?.scene).isEqualTo(SceneB)
+    }
+
+    @Test
+    fun overscrollDsl_definedForFromScene() = runMonotonicClockTest {
+        val progress = mutableStateOf(0f)
+        val state =
+            startOverscrollableTransistionFromAtoB(
+                progress = { progress.value },
+                sceneTransitions =
+                    transitions {
+                        overscroll(SceneA, Orientation.Vertical) { fade(TestElements.Foo) }
+                    }
+            )
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // overscroll for SceneA is defined
+        progress.value = -0.1f
+        assertThat(state.currentOverscrollSpec).isNotNull()
+        assertThat(state.currentOverscrollSpec?.scene).isEqualTo(SceneA)
+
+        // scroll from SceneA to SceneB
+        progress.value = 0.5f
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        progress.value = 1f
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // overscroll for SceneB is NOT defined
+        progress.value = 1.1f
+        assertThat(state.currentOverscrollSpec).isNull()
+    }
+
+    @Test
+    fun overscrollDsl_notDefinedScenes() = runMonotonicClockTest {
+        val progress = mutableStateOf(0f)
+        val state =
+            startOverscrollableTransistionFromAtoB(
+                progress = { progress.value },
+                sceneTransitions = transitions {}
+            )
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // overscroll for SceneA is NOT defined
+        progress.value = -0.1f
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // scroll from SceneA to SceneB
+        progress.value = 0.5f
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        progress.value = 1f
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // overscroll for SceneB is NOT defined
+        progress.value = 1.1f
+        assertThat(state.currentOverscrollSpec).isNull()
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index 543ed04..99372a5 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -16,9 +16,11 @@
 
 package com.android.compose.animation.scene
 
+import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.size
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
@@ -33,6 +35,7 @@
 import androidx.compose.ui.test.performTouchInput
 import androidx.compose.ui.test.swipeWithVelocity
 import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.dp
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.google.common.truth.Truth.assertThat
@@ -61,8 +64,10 @@
 
     @get:Rule val rule = createComposeRule()
 
-    private fun layoutState(initialScene: SceneKey = TestScenes.SceneA) =
-        MutableSceneTransitionLayoutState(initialScene, EmptyTestTransitions)
+    private fun layoutState(
+        initialScene: SceneKey = TestScenes.SceneA,
+        transitions: SceneTransitions = EmptyTestTransitions,
+    ) = MutableSceneTransitionLayoutState(initialScene, transitions)
 
     /** The content under test. */
     @Composable
@@ -370,8 +375,16 @@
         // detected as a drag event.
         var touchSlop = 0f
 
-        val layoutState = layoutState()
         val verticalSwipeDistance = 50.dp
+        val layoutState =
+            layoutState(
+                transitions =
+                    transitions {
+                        from(TestScenes.SceneA, to = TestScenes.SceneB) {
+                            distance = FixedDistance(verticalSwipeDistance)
+                        }
+                    }
+            )
         assertThat(verticalSwipeDistance).isNotEqualTo(LayoutHeight)
 
         rule.setContent {
@@ -383,14 +396,7 @@
             ) {
                 scene(
                     TestScenes.SceneA,
-                    userActions =
-                        mapOf(
-                            Swipe.Down to
-                                UserActionResult(
-                                    toScene = TestScenes.SceneB,
-                                    distance = verticalSwipeDistance,
-                                )
-                        ),
+                    userActions = mapOf(Swipe.Down to TestScenes.SceneB),
                 ) {
                     Spacer(Modifier.fillMaxSize())
                 }
@@ -548,4 +554,64 @@
         assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB)).isTrue()
         assertThat(state.transformationSpec.transformations).hasSize(2)
     }
+
+    @Test
+    fun dynamicSwipeDistance() {
+        val swipeDistance =
+            object : UserActionDistance {
+                override fun UserActionDistanceScope.absoluteDistance(
+                    fromSceneSize: IntSize,
+                    orientation: Orientation,
+                ): Float {
+                    // Foo is going to have a vertical offset of 50dp. Let's make the swipe distance
+                    // the difference between the bottom of the scene and the bottom of the element,
+                    // so that we use the offset and size of the element as well as the size of the
+                    // scene.
+                    val fooSize = TestElements.Foo.targetSize(TestScenes.SceneB) ?: return 0f
+                    val fooOffset = TestElements.Foo.targetOffset(TestScenes.SceneB) ?: return 0f
+                    val sceneSize = TestScenes.SceneB.targetSize() ?: return 0f
+                    return sceneSize.height - fooOffset.y - fooSize.height
+                }
+            }
+
+        val state =
+            MutableSceneTransitionLayoutState(
+                TestScenes.SceneA,
+                transitions {
+                    from(TestScenes.SceneA, to = TestScenes.SceneB) { distance = swipeDistance }
+                }
+            )
+
+        val layoutSize = 200.dp
+        val fooYOffset = 50.dp
+        val fooSize = 25.dp
+
+        var touchSlop = 0f
+        rule.setContent {
+            touchSlop = LocalViewConfiguration.current.touchSlop
+
+            SceneTransitionLayout(state, Modifier.size(layoutSize)) {
+                scene(TestScenes.SceneA, userActions = mapOf(Swipe.Up to TestScenes.SceneB)) {
+                    Box(Modifier.fillMaxSize())
+                }
+                scene(TestScenes.SceneB) {
+                    Box(Modifier.fillMaxSize()) {
+                        Box(Modifier.offset(y = fooYOffset).element(TestElements.Foo).size(fooSize))
+                    }
+                }
+            }
+        }
+
+        // Swipe up by half the expected distance to get to 50% progress.
+        val expectedDistance = layoutSize - fooYOffset - fooSize
+        rule.onRoot().performTouchInput {
+            val middle = (layoutSize / 2).toPx()
+            down(Offset(middle, middle))
+            moveBy(Offset(0f, -touchSlop - (expectedDistance / 2f).toPx()), delayMillis = 1_000)
+        }
+
+        rule.waitForIdle()
+        assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB)).isTrue()
+        assertThat(state.currentTransition!!.progress).isWithin(0.01f).of(0.5f)
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
index 1beafcc..c9c3ecc 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
@@ -20,9 +20,11 @@
 import androidx.compose.animation.core.TweenSpec
 import androidx.compose.animation.core.spring
 import androidx.compose.animation.core.tween
+import androidx.compose.foundation.gestures.Orientation
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.compose.animation.scene.transformation.Transformation
 import com.android.compose.animation.scene.transformation.TransformationRange
+import com.android.compose.animation.scene.transformation.Translate
 import com.google.common.truth.Correspondence
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
@@ -223,6 +225,17 @@
             .isSameInstanceAs(specFromAToC)
     }
 
+    @Test
+    fun overscrollSpec() {
+        val transitions = transitions {
+            overscroll(TestScenes.SceneA, Orientation.Vertical) { translate(TestElements.Bar) }
+        }
+
+        val overscrollSpec = transitions.overscrollSpecs.single()
+        val transformation = overscrollSpec.transformationSpec.transformations.single()
+        assertThat(transformation).isInstanceOf(Translate::class.java)
+    }
+
     companion object {
         private val TRANSFORMATION_RANGE =
             Correspondence.transforming<Transformation, TransformationRange?>(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
index c385788..7707a60 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
@@ -17,6 +17,8 @@
 package com.android.keyguard
 
 import android.testing.TestableLooper
+import android.view.KeyEvent
+import android.view.View
 import android.view.ViewGroup
 import android.view.inputmethod.InputMethodManager
 import android.widget.EditText
@@ -25,8 +27,8 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.util.LatencyTracker
 import com.android.internal.widget.LockPatternUtils
+import com.android.internal.widget.LockscreenCredential
 import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor
-import com.android.systemui.Flags as AconfigFlags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.flags.FakeFeatureFlags
@@ -36,12 +38,17 @@
 import com.android.systemui.statusbar.policy.DevicePostureController
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers.anyBoolean
 import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Captor
 import org.mockito.Mock
 import org.mockito.Mockito
 import org.mockito.Mockito.mock
@@ -49,6 +56,7 @@
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
+import com.android.systemui.Flags as AconfigFlags
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
@@ -77,6 +85,7 @@
     private lateinit var mKeyguardMessageAreaController:
         KeyguardMessageAreaController<BouncerKeyguardMessageArea>
     @Mock private lateinit var postureController: DevicePostureController
+    @Captor private lateinit var keyListenerArgumentCaptor: ArgumentCaptor<View.OnKeyListener>
 
     private lateinit var keyguardPasswordViewController: KeyguardPasswordViewController
 
@@ -171,4 +180,34 @@
         keyguardPasswordViewController.resetState()
         verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_password)
     }
+
+    @Test
+    fun testSpaceKeyDoesNotSubmitPassword() {
+        keyguardPasswordViewController.onViewAttached()
+        verify(passwordEntry).setOnKeyListener(keyListenerArgumentCaptor.capture())
+
+        val eventHandled =
+            keyListenerArgumentCaptor.value.onKey(keyguardPasswordView,
+                KeyEvent.KEYCODE_SPACE,
+                KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SPACE))
+
+        assertFalse("Unlock attempted.", eventHandled)
+    }
+
+    @Test
+    fun testEnterKeySubmitsPassword() {
+        val password = mock<LockscreenCredential>()
+        `when`(keyguardPasswordView.enteredCredential).thenReturn(password)
+        `when`(password.size()).thenReturn(4)
+        `when`(password.duplicate()).thenReturn(password)
+        keyguardPasswordViewController.onViewAttached()
+        verify(passwordEntry).setOnKeyListener(keyListenerArgumentCaptor.capture())
+
+        val eventHandled =
+            keyListenerArgumentCaptor.value.onKey(keyguardPasswordView,
+                KeyEvent.KEYCODE_ENTER,
+                KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER))
+
+        assertTrue("Unlock not attempted.", eventHandled)
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index 38dc24e..9dbeeda 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -31,6 +31,7 @@
 import android.widget.FrameLayout
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.internal.logging.MetricsLogger
 import com.android.internal.logging.UiEventLogger
 import com.android.internal.widget.LockPatternUtils
@@ -65,8 +66,7 @@
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
 import com.android.systemui.scene.shared.model.FakeSceneDataSource
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.shared.model.fakeSceneDataSource
 import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
 import com.android.systemui.statusbar.policy.ConfigurationController
@@ -244,7 +244,7 @@
         sceneInteractor = kosmos.sceneInteractor
         keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor
         sceneTransitionStateFlow =
-            MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Lockscreen))
+            MutableStateFlow(ObservableTransitionState.Idle(Scenes.Lockscreen))
         sceneInteractor.setTransitionState(sceneTransitionStateFlow)
         deviceEntryInteractor = kosmos.deviceEntryInteractor
 
@@ -815,18 +815,18 @@
             // not enough to trigger a dismissal of the keyguard.
             underTest.onViewAttached()
             fakeSceneDataSource.pause()
-            sceneInteractor.changeScene(SceneKey.Bouncer, "reason")
+            sceneInteractor.changeScene(Scenes.Bouncer, "reason")
             sceneTransitionStateFlow.value =
                 ObservableTransitionState.Transition(
-                    SceneKey.Lockscreen,
-                    SceneKey.Bouncer,
+                    Scenes.Lockscreen,
+                    Scenes.Bouncer,
                     flowOf(.5f),
                     false,
                     isUserInputOngoing = flowOf(false),
                 )
             runCurrent()
-            fakeSceneDataSource.unpause(expectedScene = SceneKey.Bouncer)
-            sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Bouncer)
+            fakeSceneDataSource.unpause(expectedScene = Scenes.Bouncer)
+            sceneTransitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Bouncer)
             runCurrent()
             verify(viewMediatorCallback, never()).keyguardDone(anyInt())
 
@@ -835,18 +835,18 @@
             kosmos.fakeDeviceEntryRepository.setUnlocked(true)
             runCurrent()
             fakeSceneDataSource.pause()
-            sceneInteractor.changeScene(SceneKey.Gone, "reason")
+            sceneInteractor.changeScene(Scenes.Gone, "reason")
             sceneTransitionStateFlow.value =
                 ObservableTransitionState.Transition(
-                    SceneKey.Bouncer,
-                    SceneKey.Gone,
+                    Scenes.Bouncer,
+                    Scenes.Gone,
                     flowOf(.5f),
                     false,
                     isUserInputOngoing = flowOf(false),
                 )
             runCurrent()
-            fakeSceneDataSource.unpause(expectedScene = SceneKey.Gone)
-            sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Gone)
+            fakeSceneDataSource.unpause(expectedScene = Scenes.Gone)
+            sceneTransitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Gone)
             runCurrent()
             verify(viewMediatorCallback).keyguardDone(anyInt())
 
@@ -854,18 +854,18 @@
             // again.
             clearInvocations(viewMediatorCallback)
             fakeSceneDataSource.pause()
-            sceneInteractor.changeScene(SceneKey.Bouncer, "reason")
+            sceneInteractor.changeScene(Scenes.Bouncer, "reason")
             sceneTransitionStateFlow.value =
                 ObservableTransitionState.Transition(
-                    SceneKey.Gone,
-                    SceneKey.Bouncer,
+                    Scenes.Gone,
+                    Scenes.Bouncer,
                     flowOf(.5f),
                     false,
                     isUserInputOngoing = flowOf(false),
                 )
             runCurrent()
-            fakeSceneDataSource.unpause(expectedScene = SceneKey.Bouncer)
-            sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Bouncer)
+            fakeSceneDataSource.unpause(expectedScene = Scenes.Bouncer)
+            sceneTransitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Bouncer)
             runCurrent()
             verify(viewMediatorCallback, never()).keyguardDone(anyInt())
 
@@ -874,35 +874,35 @@
             // does not dismiss the keyguard while we're not listening.
             underTest.onViewDetached()
             fakeSceneDataSource.pause()
-            sceneInteractor.changeScene(SceneKey.Gone, "reason")
+            sceneInteractor.changeScene(Scenes.Gone, "reason")
             sceneTransitionStateFlow.value =
                 ObservableTransitionState.Transition(
-                    SceneKey.Bouncer,
-                    SceneKey.Gone,
+                    Scenes.Bouncer,
+                    Scenes.Gone,
                     flowOf(.5f),
                     false,
                     isUserInputOngoing = flowOf(false),
                 )
             runCurrent()
-            fakeSceneDataSource.unpause(expectedScene = SceneKey.Gone)
-            sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Gone)
+            fakeSceneDataSource.unpause(expectedScene = Scenes.Gone)
+            sceneTransitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Gone)
             runCurrent()
             verify(viewMediatorCallback, never()).keyguardDone(anyInt())
 
             // While not listening, moving to the lockscreen does not dismiss the keyguard.
             fakeSceneDataSource.pause()
-            sceneInteractor.changeScene(SceneKey.Lockscreen, "reason")
+            sceneInteractor.changeScene(Scenes.Lockscreen, "reason")
             sceneTransitionStateFlow.value =
                 ObservableTransitionState.Transition(
-                    SceneKey.Gone,
-                    SceneKey.Lockscreen,
+                    Scenes.Gone,
+                    Scenes.Lockscreen,
                     flowOf(.5f),
                     false,
                     isUserInputOngoing = flowOf(false),
                 )
             runCurrent()
-            fakeSceneDataSource.unpause(expectedScene = SceneKey.Lockscreen)
-            sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Lockscreen)
+            fakeSceneDataSource.unpause(expectedScene = Scenes.Lockscreen)
+            sceneTransitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
             runCurrent()
             verify(viewMediatorCallback, never()).keyguardDone(anyInt())
 
@@ -910,18 +910,18 @@
             // gone scene now does dismiss the keyguard again, this time from lockscreen.
             underTest.onViewAttached()
             fakeSceneDataSource.pause()
-            sceneInteractor.changeScene(SceneKey.Gone, "reason")
+            sceneInteractor.changeScene(Scenes.Gone, "reason")
             sceneTransitionStateFlow.value =
                 ObservableTransitionState.Transition(
-                    SceneKey.Lockscreen,
-                    SceneKey.Gone,
+                    Scenes.Lockscreen,
+                    Scenes.Gone,
                     flowOf(.5f),
                     false,
                     isUserInputOngoing = flowOf(false),
                 )
             runCurrent()
-            fakeSceneDataSource.unpause(expectedScene = SceneKey.Gone)
-            sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Gone)
+            fakeSceneDataSource.unpause(expectedScene = Scenes.Gone)
+            sceneTransitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Gone)
             runCurrent()
             verify(viewMediatorCallback).keyguardDone(anyInt())
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/data/repository/AssistRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/data/repository/AssistRepositoryTest.kt
new file mode 100644
index 0000000..80077a21
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/data/repository/AssistRepositoryTest.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.assist.data.repository
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AssistRepositoryTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+
+    private val underTest = kosmos.assistRepository
+
+    @Test
+    fun invocationType() =
+        testScope.runTest {
+            val invocationType by collectLastValue(underTest.latestInvocationType)
+            underTest.setLatestInvocationType(2)
+            runCurrent()
+
+            assertThat(invocationType).isEqualTo(2)
+        }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/domain/interactor/AssistInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/domain/interactor/AssistInteractorTest.kt
new file mode 100644
index 0000000..c12f1ac
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/domain/interactor/AssistInteractorTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.assist.domain.interactor
+
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class AssistInteractorTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+
+    private val underTest = kosmos.assistInteractor
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_CONTEXTUAL_TIPS, Flags.FLAG_ENABLE_CONTEXTUAL_TIP_FOR_POWER_OFF)
+    fun onAssistantStarted() =
+        testScope.runTest {
+            val invocationType by collectLastValue(underTest.latestInvocationType)
+            underTest.onAssistantStarted(3)
+            runCurrent()
+
+            assertThat(invocationType).isEqualTo(3)
+        }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index 5034631..92eb8f8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -30,6 +30,7 @@
 import android.view.Surface
 import android.view.Surface.Rotation
 import android.view.View
+import android.view.ViewGroup
 import android.view.WindowManager
 import android.view.accessibility.AccessibilityManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -46,7 +47,12 @@
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.FromAodTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.power.data.repository.FakePowerRepository
 import com.android.systemui.power.domain.interactor.PowerInteractor
@@ -127,7 +133,8 @@
     @Mock private lateinit var defaultUdfpsTouchOverlayViewModel: DefaultUdfpsTouchOverlayViewModel
     @Mock
     private lateinit var udfpsKeyguardAccessibilityDelegate: UdfpsKeyguardAccessibilityDelegate
-    @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
+    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
     @Mock private lateinit var shadeInteractor: ShadeInteractor
     @Captor private lateinit var layoutParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams>
     @Mock private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor
@@ -150,6 +157,19 @@
                 mock(ScreenOffAnimationController::class.java),
                 statusBarStateController,
             )
+        keyguardTransitionRepository = FakeKeyguardTransitionRepository()
+        keyguardTransitionInteractor =
+            KeyguardTransitionInteractor(
+                scope = testScope.backgroundScope,
+                repository = keyguardTransitionRepository,
+                fromLockscreenTransitionInteractor = {
+                    mock(FromLockscreenTransitionInteractor::class.java)
+                },
+                fromPrimaryBouncerTransitionInteractor = {
+                    mock(FromPrimaryBouncerTransitionInteractor::class.java)
+                },
+                fromAodTransitionInteractor = { mock(FromAodTransitionInteractor::class.java) },
+            )
         whenever(inflater.inflate(R.layout.udfps_view, null, false)).thenReturn(udfpsView)
         whenever(inflater.inflate(R.layout.udfps_bp_view, null))
             .thenReturn(mock(UdfpsBpView::class.java))
@@ -159,11 +179,25 @@
             .thenReturn(mock(UdfpsFpmEmptyView::class.java))
     }
 
+    private suspend fun withReasonSuspend(
+        @RequestReason reason: Int,
+        isDebuggable: Boolean = false,
+        enableDeviceEntryUdfpsRefactor: Boolean = false,
+        block: suspend () -> Unit,
+    ) {
+        withReason(
+            reason,
+            isDebuggable,
+            enableDeviceEntryUdfpsRefactor,
+        )
+        block()
+    }
+
     private fun withReason(
         @RequestReason reason: Int,
         isDebuggable: Boolean = false,
         enableDeviceEntryUdfpsRefactor: Boolean = false,
-        block: () -> Unit,
+        block: () -> Unit = {},
     ) {
         if (enableDeviceEntryUdfpsRefactor) {
             mSetFlagsRule.enableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
@@ -312,6 +346,7 @@
                     lastWakeReason = WakeSleepReason.POWER_BUTTON,
                     lastSleepReason = WakeSleepReason.OTHER,
                 )
+                runCurrent()
                 controllerOverlay.show(udfpsController, overlayParams)
                 runCurrent()
                 verify(windowManager).addView(any(), any())
@@ -321,15 +356,25 @@
     @Test
     fun showUdfpsOverlay_whileGoingToSleep() =
         testScope.runTest {
-            withReason(REASON_AUTH_KEYGUARD) {
+            withReasonSuspend(REASON_AUTH_KEYGUARD) {
                 mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE)
+                keyguardTransitionRepository.sendTransitionSteps(
+                    from = KeyguardState.OFF,
+                    to = KeyguardState.GONE,
+                    testScope = this,
+                )
                 powerRepository.updateWakefulness(
                     rawState = WakefulnessState.STARTING_TO_SLEEP,
                     lastWakeReason = WakeSleepReason.POWER_BUTTON,
                     lastSleepReason = WakeSleepReason.OTHER,
                 )
+                runCurrent()
+
+                // WHEN a request comes to show the view
                 controllerOverlay.show(udfpsController, overlayParams)
                 runCurrent()
+
+                // THEN the view does not get added immediately
                 verify(windowManager, never()).addView(any(), any())
 
                 // we hide to end the job that listens for the finishedGoingToSleep signal
@@ -338,25 +383,82 @@
         }
 
     @Test
-    fun showUdfpsOverlay_afterFinishedGoingToSleep() =
+    fun showUdfpsOverlay_whileAsleep() =
         testScope.runTest {
-            withReason(REASON_AUTH_KEYGUARD) {
+            withReasonSuspend(REASON_AUTH_KEYGUARD) {
                 mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE)
-                powerRepository.updateWakefulness(
-                    rawState = WakefulnessState.STARTING_TO_SLEEP,
-                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
-                    lastSleepReason = WakeSleepReason.OTHER,
+                keyguardTransitionRepository.sendTransitionSteps(
+                    from = KeyguardState.OFF,
+                    to = KeyguardState.GONE,
+                    testScope = this,
                 )
-                controllerOverlay.show(udfpsController, overlayParams)
-                runCurrent()
-                verify(windowManager, never()).addView(any(), any())
-
                 powerRepository.updateWakefulness(
                     rawState = WakefulnessState.ASLEEP,
                     lastWakeReason = WakeSleepReason.POWER_BUTTON,
                     lastSleepReason = WakeSleepReason.OTHER,
                 )
                 runCurrent()
+
+                // WHEN a request comes to show the view
+                controllerOverlay.show(udfpsController, overlayParams)
+                runCurrent()
+
+                // THEN view isn't added yet
+                verify(windowManager, never()).addView(any(), any())
+
+                // we hide to end the job that listens for the finishedGoingToSleep signal
+                controllerOverlay.hide()
+            }
+        }
+
+    @Test
+    fun neverRemoveViewThatHasNotBeenAdded() =
+        testScope.runTest {
+            withReasonSuspend(REASON_AUTH_KEYGUARD) {
+                mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE)
+                controllerOverlay.show(udfpsController, overlayParams)
+                val view = controllerOverlay.getTouchOverlay()
+                view?.let {
+                    // parent is null, signalling that the view was never added
+                    whenever(view.parent).thenReturn(null)
+                }
+                verify(windowManager, never()).removeView(eq(view))
+            }
+        }
+
+    @Test
+    fun showUdfpsOverlay_afterFinishedTransitioningToAOD() =
+        testScope.runTest {
+            withReasonSuspend(REASON_AUTH_KEYGUARD) {
+                mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE)
+                keyguardTransitionRepository.sendTransitionSteps(
+                    from = KeyguardState.OFF,
+                    to = KeyguardState.GONE,
+                    testScope = this,
+                )
+                powerRepository.updateWakefulness(
+                    rawState = WakefulnessState.STARTING_TO_SLEEP,
+                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                    lastSleepReason = WakeSleepReason.OTHER,
+                )
+                runCurrent()
+
+                // WHEN a request comes to show the view
+                controllerOverlay.show(udfpsController, overlayParams)
+                runCurrent()
+
+                // THEN the view does not get added immediately
+                verify(windowManager, never()).addView(any(), any())
+
+                // WHEN the device finishes transitioning to AOD
+                keyguardTransitionRepository.sendTransitionSteps(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                    testScope = this,
+                )
+                runCurrent()
+
+                // THEN the view gets added
                 verify(windowManager)
                     .addView(eq(controllerOverlay.getTouchOverlay()), layoutParamsCaptor.capture())
             }
@@ -387,6 +489,7 @@
     private fun hideUdfpsOverlay() {
         val didShow = controllerOverlay.show(udfpsController, overlayParams)
         val view = controllerOverlay.getTouchOverlay()
+        view?.let { whenever(view.parent).thenReturn(mock(ViewGroup::class.java)) }
         val didHide = controllerOverlay.hide()
 
         verify(windowManager).removeView(eq(view))
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 561cdbb..9b0b5de 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -63,6 +63,7 @@
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewRootImpl;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
@@ -234,6 +235,8 @@
     private ArgumentCaptor<IUdfpsOverlayController> mOverlayCaptor;
     private IUdfpsOverlayController mOverlayController;
     @Captor
+    private ArgumentCaptor<View> mViewCaptor;
+    @Captor
     private ArgumentCaptor<UdfpsView.OnTouchListener> mTouchListenerCaptor;
     @Captor
     private ArgumentCaptor<View.OnHoverListener> mHoverListenerCaptor;
@@ -550,8 +553,11 @@
                                     mOpticalProps.sensorId,
                                     BiometricRequestConstants.REASON_ENROLL_ENROLLING,
                                     mUdfpsOverlayControllerCallback);
+
                             mFgExecutor.runAllReady();
-                            verify(mWindowManager).addView(any(), any());
+                            verify(mWindowManager).addView(mViewCaptor.capture(), any());
+                            when(mViewCaptor.getValue().getParent())
+                                    .thenReturn(mock(ViewGroup.class));
 
                             // Update overlay parameters.
                             reset(mWindowManager);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
index ad29e68..df50eb6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
@@ -19,6 +19,7 @@
 import android.content.pm.UserInfo
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
 import com.android.systemui.authentication.domain.interactor.authenticationInteractor
@@ -33,7 +34,7 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.res.R
 import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.testKosmos
 import com.android.systemui.user.data.model.SelectedUserModel
 import com.android.systemui.user.data.model.SelectionStatus
@@ -93,7 +94,7 @@
 
             assertThat(message?.text).isEqualTo(ENTER_YOUR_PASSWORD)
             assertThat(password).isEmpty()
-            assertThat(currentScene).isEqualTo(SceneKey.Bouncer)
+            assertThat(currentScene).isEqualTo(Scenes.Bouncer)
             assertThat(underTest.authenticationMethod).isEqualTo(AuthenticationMethodModel.Password)
         }
 
@@ -125,7 +126,7 @@
 
             assertThat(message?.text).isEmpty()
             assertThat(password).isEqualTo("password")
-            assertThat(currentScene).isEqualTo(SceneKey.Bouncer)
+            assertThat(currentScene).isEqualTo(Scenes.Bouncer)
         }
 
     @Test
@@ -163,7 +164,7 @@
                 AuthenticationMethodModel.Password
             )
             kosmos.fakeDeviceEntryRepository.setUnlocked(false)
-            switchToScene(SceneKey.Bouncer)
+            switchToScene(Scenes.Bouncer)
 
             // No input entered.
 
@@ -209,14 +210,14 @@
             assertThat(password).isEqualTo("password")
 
             // The user doesn't confirm the password, but navigates back to the lockscreen instead.
-            switchToScene(SceneKey.Lockscreen)
+            switchToScene(Scenes.Lockscreen)
 
             // The user navigates to the bouncer again.
-            switchToScene(SceneKey.Bouncer)
+            switchToScene(Scenes.Bouncer)
 
             // Ensure the previously-entered password is not shown.
             assertThat(password).isEmpty()
-            assertThat(currentScene).isEqualTo(SceneKey.Bouncer)
+            assertThat(currentScene).isEqualTo(Scenes.Bouncer)
         }
 
     @Test
@@ -330,8 +331,8 @@
 
     private fun TestScope.switchToScene(toScene: SceneKey) {
         val currentScene by collectLastValue(sceneInteractor.currentScene)
-        val bouncerShown = currentScene != SceneKey.Bouncer && toScene == SceneKey.Bouncer
-        val bouncerHidden = currentScene == SceneKey.Bouncer && toScene != SceneKey.Bouncer
+        val bouncerShown = currentScene != Scenes.Bouncer && toScene == Scenes.Bouncer
+        val bouncerHidden = currentScene == Scenes.Bouncer && toScene != Scenes.Bouncer
         sceneInteractor.changeScene(toScene, "reason")
         if (bouncerShown) underTest.onShown()
         if (bouncerHidden) underTest.onHidden()
@@ -345,7 +346,7 @@
             AuthenticationMethodModel.Password
         )
         kosmos.fakeDeviceEntryRepository.setUnlocked(false)
-        switchToScene(SceneKey.Bouncer)
+        switchToScene(Scenes.Bouncer)
     }
 
     private suspend fun TestScope.setLockout(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
index 32de1f2..91a056d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
@@ -18,6 +18,7 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
 import com.android.systemui.authentication.data.repository.authenticationRepository
@@ -31,7 +32,7 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.res.R
 import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
@@ -86,7 +87,7 @@
             assertThat(message?.text).isEqualTo(ENTER_YOUR_PATTERN)
             assertThat(selectedDots).isEmpty()
             assertThat(currentDot).isNull()
-            assertThat(currentScene).isEqualTo(SceneKey.Bouncer)
+            assertThat(currentScene).isEqualTo(Scenes.Bouncer)
             assertThat(underTest.authenticationMethod).isEqualTo(AuthenticationMethodModel.Pattern)
         }
 
@@ -104,7 +105,7 @@
             assertThat(message?.text).isEmpty()
             assertThat(selectedDots).isEmpty()
             assertThat(currentDot).isNull()
-            assertThat(currentScene).isEqualTo(SceneKey.Bouncer)
+            assertThat(currentScene).isEqualTo(Scenes.Bouncer)
         }
 
     @Test
@@ -159,7 +160,7 @@
             assertThat(selectedDots).isEmpty()
             assertThat(currentDot).isNull()
             assertThat(message?.text).isEqualTo(WRONG_PATTERN)
-            assertThat(currentScene).isEqualTo(SceneKey.Bouncer)
+            assertThat(currentScene).isEqualTo(Scenes.Bouncer)
         }
 
     @Test
@@ -369,8 +370,8 @@
 
     private fun TestScope.switchToScene(toScene: SceneKey) {
         val currentScene by collectLastValue(sceneInteractor.currentScene)
-        val bouncerShown = currentScene != SceneKey.Bouncer && toScene == SceneKey.Bouncer
-        val bouncerHidden = currentScene == SceneKey.Bouncer && toScene != SceneKey.Bouncer
+        val bouncerShown = currentScene != Scenes.Bouncer && toScene == Scenes.Bouncer
+        val bouncerHidden = currentScene == Scenes.Bouncer && toScene != Scenes.Bouncer
         sceneInteractor.changeScene(toScene, "reason")
         if (bouncerShown) underTest.onShown()
         if (bouncerHidden) underTest.onHidden()
@@ -384,7 +385,7 @@
             AuthenticationMethodModel.Pattern
         )
         kosmos.fakeDeviceEntryRepository.setUnlocked(false)
-        switchToScene(SceneKey.Bouncer)
+        switchToScene(Scenes.Bouncer)
     }
 
     companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
index ccf7094..7b75a37 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
@@ -18,6 +18,7 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
 import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
@@ -31,7 +32,7 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.res.R
 import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -196,7 +197,7 @@
 
             assertThat(message?.text).isEmpty()
             assertThat(pin).isEmpty()
-            assertThat(currentScene).isEqualTo(SceneKey.Bouncer)
+            assertThat(currentScene).isEqualTo(Scenes.Bouncer)
         }
 
     @Test
@@ -230,7 +231,7 @@
 
             assertThat(pin).isEmpty()
             assertThat(message?.text).ignoringCase().isEqualTo(WRONG_PIN)
-            assertThat(currentScene).isEqualTo(SceneKey.Bouncer)
+            assertThat(currentScene).isEqualTo(Scenes.Bouncer)
         }
 
     @Test
@@ -290,7 +291,7 @@
 
             assertThat(pin).isEmpty()
             assertThat(message?.text).ignoringCase().isEqualTo(WRONG_PIN)
-            assertThat(currentScene).isEqualTo(SceneKey.Bouncer)
+            assertThat(currentScene).isEqualTo(Scenes.Bouncer)
         }
 
     @Test
@@ -304,10 +305,10 @@
             assertThat(pin).isNotEmpty()
 
             // The user doesn't confirm the PIN, but navigates back to the lockscreen instead.
-            switchToScene(SceneKey.Lockscreen)
+            switchToScene(Scenes.Lockscreen)
 
             // The user navigates to the bouncer again.
-            switchToScene(SceneKey.Bouncer)
+            switchToScene(Scenes.Bouncer)
 
             // Ensure the previously-entered PIN is not shown.
             assertThat(pin).isEmpty()
@@ -389,8 +390,8 @@
 
     private fun TestScope.switchToScene(toScene: SceneKey) {
         val currentScene by collectLastValue(sceneInteractor.currentScene)
-        val bouncerShown = currentScene != SceneKey.Bouncer && toScene == SceneKey.Bouncer
-        val bouncerHidden = currentScene == SceneKey.Bouncer && toScene != SceneKey.Bouncer
+        val bouncerShown = currentScene != Scenes.Bouncer && toScene == Scenes.Bouncer
+        val bouncerHidden = currentScene == Scenes.Bouncer && toScene != Scenes.Bouncer
         sceneInteractor.changeScene(toScene, "reason")
         if (bouncerShown) underTest.onShown()
         if (bouncerHidden) underTest.onHidden()
@@ -402,7 +403,7 @@
     private fun TestScope.lockDeviceAndOpenPinBouncer() {
         kosmos.fakeAuthenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
         kosmos.fakeDeviceEntryRepository.setUnlocked(false)
-        switchToScene(SceneKey.Bouncer)
+        switchToScene(Scenes.Bouncer)
     }
 
     companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/camera/data/repository/CameraAutoRotateRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/camera/data/repository/CameraAutoRotateRepositoryImplTest.kt
new file mode 100644
index 0000000..9cfa572
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/camera/data/repository/CameraAutoRotateRepositoryImplTest.kt
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.camera.data.repository
+
+import android.os.UserHandle
+import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.util.settings.fakeSettings
+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
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@android.platform.test.annotations.EnabledOnRavenwood
+class CameraAutoRotateRepositoryImplTest : SysuiTestCase() {
+    private val kosmos = Kosmos()
+    private val testScope = kosmos.testScope
+    private val settings = kosmos.fakeSettings
+    private val testUser = UserHandle.of(1)
+
+    private val underTest =
+        CameraAutoRotateRepositoryImpl(settings, testScope.testScheduler, testScope.backgroundScope)
+
+    /** 3 changes => 3 change signals + 1 signal emitted at start => 4 signals */
+    @Test
+    fun isCameraAutoRotateSettingEnabled_3times() =
+        testScope.runTest {
+            settings.putIntForUser(SETTING_NAME, DISABLE, testUser.identifier)
+            val isCameraAutoRotateSettingEnabled by
+                collectValues(underTest.isCameraAutoRotateSettingEnabled(testUser))
+            runCurrent()
+            assertThat(isCameraAutoRotateSettingEnabled.last()).isFalse()
+
+            settings.putIntForUser(SETTING_NAME, ENABLE, testUser.identifier)
+            runCurrent()
+            assertThat(isCameraAutoRotateSettingEnabled.last()).isTrue()
+
+            settings.putIntForUser(SETTING_NAME, DISABLE, testUser.identifier)
+            runCurrent()
+            assertThat(isCameraAutoRotateSettingEnabled.last()).isFalse()
+
+            settings.putIntForUser(SETTING_NAME, ENABLE, testUser.identifier)
+            runCurrent()
+            assertThat(isCameraAutoRotateSettingEnabled.last()).isTrue()
+
+            assertThat(isCameraAutoRotateSettingEnabled).hasSize(4)
+        }
+
+    @Test
+    fun isCameraAutoRotateSettingEnabled_emitsOnStart() =
+        testScope.runTest {
+            val isCameraAutoRotateSettingEnabled: List<Boolean> by
+                collectValues(underTest.isCameraAutoRotateSettingEnabled(testUser))
+
+            runCurrent()
+
+            assertThat(isCameraAutoRotateSettingEnabled).hasSize(1)
+        }
+
+    /** 0 for 0 changes + 1 signal emitted on start => 1 signal */
+    @Test
+    fun isCameraAutoRotateSettingEnabled_0Times() =
+        testScope.runTest {
+            settings.putIntForUser(SETTING_NAME, DISABLE, testUser.identifier)
+            val isCameraAutoRotateSettingEnabled: List<Boolean> by
+                collectValues(underTest.isCameraAutoRotateSettingEnabled(testUser))
+            runCurrent()
+
+            settings.putIntForUser(SETTING_NAME, DISABLE, testUser.identifier)
+            runCurrent()
+
+            assertThat(isCameraAutoRotateSettingEnabled).hasSize(1)
+            assertThat(isCameraAutoRotateSettingEnabled[0]).isFalse()
+        }
+
+    /** Maintain that flows are cached by user */
+    @Test
+    fun sameUserCallsIsCameraAutoRotateSettingEnabledTwice_getsSameFlow() =
+        testScope.runTest {
+            val flow1 = underTest.isCameraAutoRotateSettingEnabled(testUser)
+            val flow2 = underTest.isCameraAutoRotateSettingEnabled(testUser)
+
+            assertThat(flow1).isEqualTo(flow2)
+        }
+
+    @Test
+    fun differentUsersCallIsCameraAutoRotateSettingEnabled_getDifferentFlow() =
+        testScope.runTest {
+            val user2 = UserHandle.of(2)
+            val flow1 = underTest.isCameraAutoRotateSettingEnabled(testUser)
+            val flow2 = underTest.isCameraAutoRotateSettingEnabled(user2)
+
+            assertThat(flow1).isNotEqualTo(flow2)
+        }
+
+    private companion object {
+        private const val SETTING_NAME = Settings.Secure.CAMERA_AUTOROTATE
+        private const val DISABLE = 0
+        private const val ENABLE = 1
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/camera/data/repository/CameraSensorPrivacyRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/camera/data/repository/CameraSensorPrivacyRepositoryImplTest.kt
new file mode 100644
index 0000000..29de58e
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/camera/data/repository/CameraSensorPrivacyRepositoryImplTest.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.camera.data.repository
+
+import android.hardware.SensorPrivacyManager
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+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.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers
+import org.mockito.Mockito
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@android.platform.test.annotations.EnabledOnRavenwood
+class CameraSensorPrivacyRepositoryImplTest : SysuiTestCase() {
+    private val kosmos = Kosmos()
+    private val testScope = kosmos.testScope
+    private val testUser = UserHandle.of(1)
+    private val privacyManager = mock<SensorPrivacyManager>()
+    private val underTest =
+        CameraSensorPrivacyRepositoryImpl(
+            testScope.testScheduler,
+            testScope.backgroundScope,
+            privacyManager
+        )
+
+    @Test
+    fun isEnabled_2TimesForSameUserReturnsCachedFlow() =
+        testScope.runTest {
+            val flow1 = underTest.isEnabled(testUser)
+            val flow2 = underTest.isEnabled(testUser)
+            runCurrent()
+
+            assertThat(flow1).isEqualTo(flow2)
+        }
+
+    @Test
+    fun isEnabled_2TimesForDifferentUsersReturnsTwoDifferentFlows() =
+        testScope.runTest {
+            val user2 = UserHandle.of(2)
+
+            val flow1 = underTest.isEnabled(testUser)
+            val flow2 = underTest.isEnabled(user2)
+            runCurrent()
+
+            assertThat(flow1).isNotEqualTo(flow2)
+        }
+
+    @Test
+    fun isEnabled_dataMatchesSensorPrivacyManager() =
+        testScope.runTest {
+            val isEnabled = collectLastValue(underTest.isEnabled(testUser))
+
+            val captor =
+                ArgumentCaptor.forClass(
+                    SensorPrivacyManager.OnSensorPrivacyChangedListener::class.java
+                )
+            runCurrent()
+            assertThat(isEnabled()).isEqualTo(false)
+
+            Mockito.verify(privacyManager)
+                .addSensorPrivacyListener(
+                    ArgumentMatchers.eq(SensorPrivacyManager.Sensors.CAMERA),
+                    ArgumentMatchers.eq(testUser.identifier),
+                    captor.capture()
+                )
+            val sensorPrivacyCallback = captor.value!!
+
+            sensorPrivacyCallback.onSensorPrivacyChanged(SensorPrivacyManager.Sensors.CAMERA, true)
+            runCurrent()
+            assertThat(isEnabled()).isEqualTo(true)
+
+            sensorPrivacyCallback.onSensorPrivacyChanged(SensorPrivacyManager.Sensors.CAMERA, false)
+            runCurrent()
+            assertThat(isEnabled()).isEqualTo(false)
+        }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/camera/data/repository/FakeCameraAutoRotateRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/camera/data/repository/FakeCameraAutoRotateRepositoryTest.kt
new file mode 100644
index 0000000..f75e036
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/camera/data/repository/FakeCameraAutoRotateRepositoryTest.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.camera.data.repository
+
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.kosmos.Kosmos
+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
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@android.platform.test.annotations.EnabledOnRavenwood
+class FakeCameraAutoRotateRepositoryTest : SysuiTestCase() {
+    private val kosmos = Kosmos()
+    private val underTest = kosmos.fakeCameraAutoRotateRepository
+    private val testUser = UserHandle.of(1)
+
+    @Test
+    fun isCameraAutoRotateSettingEnabled_emitsFalseOnStart() = runTest {
+        val isCameraAutoRotateSettingEnabled by
+            collectValues(underTest.isCameraAutoRotateSettingEnabled(testUser))
+
+        assertThat(isCameraAutoRotateSettingEnabled).hasSize(1)
+        assertThat(isCameraAutoRotateSettingEnabled.first()).isFalse()
+    }
+
+    /**
+     * The value explicitly set in this test is not distinct, therefore only 1 value is collected.
+     */
+    @Test
+    fun isCameraAutoRotateSettingEnabled_emitsDistinctValueOnly() = runTest {
+        val isCameraAutoRotateSettingEnabled by
+            collectValues(underTest.isCameraAutoRotateSettingEnabled(testUser))
+        underTest.setEnabled(testUser, false)
+        runCurrent()
+
+        assertThat(isCameraAutoRotateSettingEnabled).hasSize(1)
+        assertThat(isCameraAutoRotateSettingEnabled.first()).isFalse()
+    }
+
+    @Test
+    fun isCameraAutoRotateSettingEnabled_canSetValue3Times() = runTest {
+        val isCameraAutoRotateSettingEnabled by
+            collectValues(underTest.isCameraAutoRotateSettingEnabled(testUser))
+        runCurrent()
+        underTest.setEnabled(testUser, true)
+        runCurrent()
+        underTest.setEnabled(testUser, false)
+        runCurrent()
+        underTest.setEnabled(testUser, true)
+        runCurrent()
+        assertThat(isCameraAutoRotateSettingEnabled).hasSize(4)
+        assertThat(isCameraAutoRotateSettingEnabled.last()).isTrue()
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/camera/data/repository/FakeCameraSensorPrivacyRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/camera/data/repository/FakeCameraSensorPrivacyRepositoryTest.kt
new file mode 100644
index 0000000..7fa1be3
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/camera/data/repository/FakeCameraSensorPrivacyRepositoryTest.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.camera.data.repository
+
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.kosmos.Kosmos
+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
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@android.platform.test.annotations.EnabledOnRavenwood
+class FakeCameraSensorPrivacyRepositoryTest : SysuiTestCase() {
+    private val kosmos = Kosmos()
+    private val underTest = kosmos.fakeCameraSensorPrivacyRepository
+    private val testUser = UserHandle.of(1)
+
+    @Test
+    fun isCameraSensorPrivacyEnabled_emitsFalseOnStart() = runTest {
+        val isCameraSensorPrivacySettingEnabled by collectValues(underTest.isEnabled(testUser))
+
+        assertThat(isCameraSensorPrivacySettingEnabled).hasSize(1)
+        assertThat(isCameraSensorPrivacySettingEnabled.first()).isFalse()
+    }
+
+    /**
+     * The value explicitly set in this test is not distinct, therefore only 1 value is collected.
+     */
+    @Test
+    fun isCameraSensorPrivacyEnabled_emitsDistinctValueOnly() = runTest {
+        val isCameraSensorPrivacySettingEnabled by collectValues(underTest.isEnabled(testUser))
+        underTest.setEnabled(testUser, false)
+        runCurrent()
+
+        assertThat(isCameraSensorPrivacySettingEnabled).hasSize(1)
+        assertThat(isCameraSensorPrivacySettingEnabled.first()).isFalse()
+    }
+
+    @Test
+    fun isCameraSensorPrivacyEnabled_canSetValue3Times() = runTest {
+        val isCameraSensorPrivacySettingEnabled by collectValues(underTest.isEnabled(testUser))
+        runCurrent()
+        underTest.setEnabled(testUser, true)
+        runCurrent()
+        underTest.setEnabled(testUser, false)
+        runCurrent()
+        underTest.setEnabled(testUser, true)
+        runCurrent()
+        assertThat(isCameraSensorPrivacySettingEnabled).hasSize(4)
+        assertThat(isCameraSensorPrivacySettingEnabled.last()).isTrue()
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
index d86b35d..ce6445b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -21,9 +21,8 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.domain.interactor.communalInteractor
 import com.android.systemui.communal.domain.interactor.setCommunalAvailable
-import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.dock.DockManager
 import com.android.systemui.dock.dockManager
 import com.android.systemui.dock.fakeDockManager
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
@@ -40,6 +39,7 @@
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -79,8 +79,8 @@
             testScope.runTest {
                 val scene by collectLastValue(communalInteractor.desiredScene)
 
-                communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
-                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+                communalInteractor.onSceneChanged(CommunalScenes.Communal)
+                assertThat(scene).isEqualTo(CommunalScenes.Communal)
 
                 fakeKeyguardTransitionRepository.sendTransitionSteps(
                     from = KeyguardState.PRIMARY_BOUNCER,
@@ -88,35 +88,17 @@
                     testScope = this
                 )
 
-                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+                assertThat(scene).isEqualTo(CommunalScenes.Blank)
             }
         }
 
-    @Test
-    fun deviceDreaming_forceBlankScene() =
-        with(kosmos) {
-            testScope.runTest {
-                val scene by collectLastValue(communalInteractor.desiredScene)
-
-                communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
-                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
-
-                fakeKeyguardTransitionRepository.sendTransitionSteps(
-                    from = KeyguardState.GLANCEABLE_HUB,
-                    to = KeyguardState.DREAMING,
-                    testScope = this
-                )
-
-                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
-            }
-        }
-
+    @Ignore("Ignored until custom animations are implemented in b/322787129")
     @Test
     fun deviceDocked_forceCommunalScene() =
         with(kosmos) {
             testScope.runTest {
                 val scene by collectLastValue(communalInteractor.desiredScene)
-                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+                assertThat(scene).isEqualTo(CommunalScenes.Blank)
 
                 updateDocked(true)
                 fakeKeyguardTransitionRepository.sendTransitionSteps(
@@ -124,14 +106,24 @@
                     to = KeyguardState.LOCKSCREEN,
                     testScope = this
                 )
-                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+                assertThat(scene).isEqualTo(CommunalScenes.Communal)
+            }
+        }
 
+    @Test
+    fun exitingDream_forceCommunalScene() =
+        with(kosmos) {
+            testScope.runTest {
+                val scene by collectLastValue(communalInteractor.desiredScene)
+                assertThat(scene).isEqualTo(CommunalScenes.Blank)
+
+                updateDocked(true)
                 fakeKeyguardTransitionRepository.sendTransitionSteps(
-                    from = KeyguardState.GLANCEABLE_HUB,
-                    to = KeyguardState.DREAMING,
+                    from = KeyguardState.DREAMING,
+                    to = KeyguardState.LOCKSCREEN,
                     testScope = this
                 )
-                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+                assertThat(scene).isEqualTo(CommunalScenes.Communal)
             }
         }
 
@@ -140,7 +132,7 @@
         with(kosmos) {
             testScope.runTest {
                 val scene by collectLastValue(communalInteractor.desiredScene)
-                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+                assertThat(scene).isEqualTo(CommunalScenes.Blank)
 
                 updateDocked(true)
                 fakeKeyguardTransitionRepository.sendTransitionSteps(
@@ -148,7 +140,7 @@
                     to = KeyguardState.LOCKSCREEN,
                     testScope = this
                 )
-                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+                assertThat(scene).isEqualTo(CommunalScenes.Blank)
             }
         }
 
@@ -157,19 +149,19 @@
         with(kosmos) {
             testScope.runTest {
                 val scene by collectLastValue(communalInteractor.desiredScene)
-                communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
-                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+                communalInteractor.onSceneChanged(CommunalScenes.Communal)
+                assertThat(scene).isEqualTo(CommunalScenes.Communal)
 
                 fakeKeyguardTransitionRepository.sendTransitionSteps(
                     from = KeyguardState.GLANCEABLE_HUB,
                     to = KeyguardState.OFF,
                     testScope = this
                 )
-                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+                assertThat(scene).isEqualTo(CommunalScenes.Communal)
 
                 advanceTimeBy(CommunalSceneStartable.AWAKE_DEBOUNCE_DELAY)
 
-                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+                assertThat(scene).isEqualTo(CommunalScenes.Blank)
             }
         }
 
@@ -178,17 +170,17 @@
         with(kosmos) {
             testScope.runTest {
                 val scene by collectLastValue(communalInteractor.desiredScene)
-                communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
-                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+                communalInteractor.onSceneChanged(CommunalScenes.Communal)
+                assertThat(scene).isEqualTo(CommunalScenes.Communal)
 
                 fakeKeyguardTransitionRepository.sendTransitionSteps(
                     from = KeyguardState.GLANCEABLE_HUB,
                     to = KeyguardState.OFF,
                     testScope = this
                 )
-                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+                assertThat(scene).isEqualTo(CommunalScenes.Communal)
                 advanceTimeBy(CommunalSceneStartable.AWAKE_DEBOUNCE_DELAY / 2)
-                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+                assertThat(scene).isEqualTo(CommunalScenes.Communal)
 
                 fakeKeyguardTransitionRepository.sendTransitionSteps(
                     from = KeyguardState.OFF,
@@ -197,15 +189,16 @@
                 )
 
                 advanceTimeBy(CommunalSceneStartable.AWAKE_DEBOUNCE_DELAY)
-                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+                assertThat(scene).isEqualTo(CommunalScenes.Communal)
             }
         }
 
+    @Ignore("Ignored until custom animations are implemented in b/322787129")
     @Test
     fun dockingOnLockscreen_forcesCommunal() =
         with(kosmos) {
             testScope.runTest {
-                communalInteractor.onSceneChanged(CommunalSceneKey.Blank)
+                communalInteractor.onSceneChanged(CommunalScenes.Blank)
                 val scene by collectLastValue(communalInteractor.desiredScene)
 
                 // device is docked while on the lockscreen
@@ -216,17 +209,18 @@
                 )
                 updateDocked(true)
 
-                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+                assertThat(scene).isEqualTo(CommunalScenes.Blank)
                 advanceTimeBy(CommunalSceneStartable.DOCK_DEBOUNCE_DELAY)
-                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
+                assertThat(scene).isEqualTo(CommunalScenes.Communal)
             }
         }
 
+    @Ignore("Ignored until custom animations are implemented in b/322787129")
     @Test
     fun dockingOnLockscreen_doesNotForceCommunalIfDreamStarts() =
         with(kosmos) {
             testScope.runTest {
-                communalInteractor.onSceneChanged(CommunalSceneKey.Blank)
+                communalInteractor.onSceneChanged(CommunalScenes.Blank)
                 val scene by collectLastValue(communalInteractor.desiredScene)
 
                 // device is docked while on the lockscreen
@@ -237,9 +231,9 @@
                 )
                 updateDocked(true)
 
-                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+                assertThat(scene).isEqualTo(CommunalScenes.Blank)
                 advanceTimeBy(CommunalSceneStartable.DOCK_DEBOUNCE_DELAY / 2)
-                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+                assertThat(scene).isEqualTo(CommunalScenes.Blank)
 
                 // dream starts shortly after docking
                 fakeKeyguardTransitionRepository.sendTransitionSteps(
@@ -248,7 +242,7 @@
                     testScope = this
                 )
                 advanceTimeBy(CommunalSceneStartable.DOCK_DEBOUNCE_DELAY)
-                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
+                assertThat(scene).isEqualTo(CommunalScenes.Blank)
             }
         }
 
@@ -256,7 +250,8 @@
         with(kosmos) {
             runCurrent()
             fakeDockManager.setIsDocked(docked)
-            fakeDockManager.setDockEvent(DockManager.STATE_DOCKED)
+            // TODO(b/322787129): uncomment once custom animations are in place
+            // fakeDockManager.setDockEvent(DockManager.STATE_DOCKED)
             runCurrent()
         }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt
index 06b3806..43acf31 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt
@@ -18,9 +18,9 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.communal.shared.model.CommunalSceneKey
-import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
+import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.scene.data.repository.sceneContainerRepository
@@ -60,20 +60,17 @@
         testScope.runTest {
             val transitionState by collectLastValue(underTest.transitionState)
             assertThat(transitionState)
-                .isEqualTo(ObservableCommunalTransitionState.Idle(CommunalSceneKey.DEFAULT))
+                .isEqualTo(ObservableTransitionState.Idle(CommunalScenes.Default))
         }
 
     @Test
     fun transitionState_setTransitionState_returnsNewValue() =
         testScope.runTest {
-            val expectedSceneKey = CommunalSceneKey.Communal
-            underTest.setTransitionState(
-                flowOf(ObservableCommunalTransitionState.Idle(expectedSceneKey))
-            )
+            val expectedSceneKey = CommunalScenes.Communal
+            underTest.setTransitionState(flowOf(ObservableTransitionState.Idle(expectedSceneKey)))
 
             val transitionState by collectLastValue(underTest.transitionState)
-            assertThat(transitionState)
-                .isEqualTo(ObservableCommunalTransitionState.Idle(expectedSceneKey))
+            assertThat(transitionState).isEqualTo(ObservableTransitionState.Idle(expectedSceneKey))
         }
 
     @Test
@@ -81,7 +78,7 @@
         testScope.runTest {
             // Set a value for the transition state flow.
             underTest.setTransitionState(
-                flowOf(ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal))
+                flowOf(ObservableTransitionState.Idle(CommunalScenes.Communal))
             )
 
             // Set the transition state flow back to null.
@@ -90,6 +87,6 @@
             // Flow returns default scene key.
             val transitionState by collectLastValue(underTest.transitionState)
             assertThat(transitionState)
-                .isEqualTo(ObservableCommunalTransitionState.Idle(CommunalSceneKey.DEFAULT))
+                .isEqualTo(ObservableTransitionState.Idle(CommunalScenes.Default))
         }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index cd29652..eafd503 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -25,8 +25,10 @@
 import android.widget.RemoteViews
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryImpl
 import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository
 import com.android.systemui.communal.data.repository.FakeCommunalPrefsRepository
 import com.android.systemui.communal.data.repository.FakeCommunalRepository
@@ -39,9 +41,8 @@
 import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository
 import com.android.systemui.communal.domain.model.CommunalContentModel
 import com.android.systemui.communal.shared.model.CommunalContentSize
-import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
-import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
 import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.flags.Flags
@@ -52,7 +53,7 @@
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.settings.FakeUserTracker
 import com.android.systemui.settings.fakeUserTracker
 import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository
@@ -62,6 +63,7 @@
 import com.android.systemui.user.data.repository.fakeUserRepository
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.settings.fakeSettings
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -460,9 +462,9 @@
 
             var desiredScene = collectLastValue(underTest.desiredScene)
             runCurrent()
-            assertThat(desiredScene()).isEqualTo(CommunalSceneKey.Blank)
+            assertThat(desiredScene()).isEqualTo(CommunalScenes.Blank)
 
-            val targetScene = CommunalSceneKey.Communal
+            val targetScene = CommunalScenes.Communal
             communalRepository.setDesiredScene(targetScene)
             desiredScene = collectLastValue(underTest.desiredScene)
             runCurrent()
@@ -472,7 +474,7 @@
     @Test
     fun updatesScene() =
         testScope.runTest {
-            val targetScene = CommunalSceneKey.Communal
+            val targetScene = CommunalScenes.Communal
 
             underTest.onSceneChanged(targetScene)
 
@@ -489,32 +491,32 @@
 
             val desiredScene by collectLastValue(underTest.desiredScene)
 
-            underTest.onSceneChanged(CommunalSceneKey.Communal)
-            assertThat(desiredScene).isEqualTo(CommunalSceneKey.Communal)
+            underTest.onSceneChanged(CommunalScenes.Communal)
+            assertThat(desiredScene).isEqualTo(CommunalScenes.Communal)
 
             kosmos.setCommunalAvailable(false)
             runCurrent()
 
             // Scene returns blank when communal is not available.
-            assertThat(desiredScene).isEqualTo(CommunalSceneKey.Blank)
+            assertThat(desiredScene).isEqualTo(CommunalScenes.Blank)
 
             kosmos.setCommunalAvailable(true)
             runCurrent()
 
             // After re-enabling, scene goes back to Communal.
-            assertThat(desiredScene).isEqualTo(CommunalSceneKey.Communal)
+            assertThat(desiredScene).isEqualTo(CommunalScenes.Communal)
         }
 
     @Test
     fun transitionProgress_onTargetScene_fullProgress() =
         testScope.runTest {
-            val targetScene = CommunalSceneKey.Blank
+            val targetScene = CommunalScenes.Blank
             val transitionProgressFlow = underTest.transitionProgressToScene(targetScene)
             val transitionProgress by collectLastValue(transitionProgressFlow)
 
             val transitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Idle(targetScene)
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(targetScene)
                 )
             underTest.setTransitionState(transitionState)
 
@@ -525,14 +527,14 @@
     @Test
     fun transitionProgress_notOnTargetScene_noProgress() =
         testScope.runTest {
-            val targetScene = CommunalSceneKey.Blank
-            val currentScene = CommunalSceneKey.Communal
+            val targetScene = CommunalScenes.Blank
+            val currentScene = CommunalScenes.Communal
             val transitionProgressFlow = underTest.transitionProgressToScene(targetScene)
             val transitionProgress by collectLastValue(transitionProgressFlow)
 
             val transitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Idle(currentScene)
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(currentScene)
                 )
             underTest.setTransitionState(transitionState)
 
@@ -543,14 +545,14 @@
     @Test
     fun transitionProgress_transitioningToTrackedScene() =
         testScope.runTest {
-            val currentScene = CommunalSceneKey.Communal
-            val targetScene = CommunalSceneKey.Blank
+            val currentScene = CommunalScenes.Communal
+            val targetScene = CommunalScenes.Blank
             val transitionProgressFlow = underTest.transitionProgressToScene(targetScene)
             val transitionProgress by collectLastValue(transitionProgressFlow)
 
             var transitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Idle(currentScene)
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(currentScene)
                 )
             underTest.setTransitionState(transitionState)
 
@@ -560,7 +562,7 @@
             val progress = MutableStateFlow(0f)
             transitionState =
                 MutableStateFlow(
-                    ObservableCommunalTransitionState.Transition(
+                    ObservableTransitionState.Transition(
                         fromScene = currentScene,
                         toScene = targetScene,
                         progress = progress,
@@ -579,7 +581,7 @@
             assertThat(transitionProgress).isEqualTo(CommunalTransitionProgress.Transition(1f))
 
             // Transition finishes.
-            transitionState = MutableStateFlow(ObservableCommunalTransitionState.Idle(targetScene))
+            transitionState = MutableStateFlow(ObservableTransitionState.Idle(targetScene))
             underTest.setTransitionState(transitionState)
             assertThat(transitionProgress).isEqualTo(CommunalTransitionProgress.Idle(targetScene))
         }
@@ -587,14 +589,14 @@
     @Test
     fun transitionProgress_transitioningAwayFromTrackedScene() =
         testScope.runTest {
-            val currentScene = CommunalSceneKey.Blank
-            val targetScene = CommunalSceneKey.Communal
+            val currentScene = CommunalScenes.Blank
+            val targetScene = CommunalScenes.Communal
             val transitionProgressFlow = underTest.transitionProgressToScene(currentScene)
             val transitionProgress by collectLastValue(transitionProgressFlow)
 
             var transitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Idle(currentScene)
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(currentScene)
                 )
             underTest.setTransitionState(transitionState)
 
@@ -604,7 +606,7 @@
             val progress = MutableStateFlow(0f)
             transitionState =
                 MutableStateFlow(
-                    ObservableCommunalTransitionState.Transition(
+                    ObservableTransitionState.Transition(
                         fromScene = currentScene,
                         toScene = targetScene,
                         progress = progress,
@@ -625,7 +627,7 @@
             assertThat(transitionProgress).isEqualTo(CommunalTransitionProgress.OtherTransition)
 
             // Transition finishes.
-            transitionState = MutableStateFlow(ObservableCommunalTransitionState.Idle(targetScene))
+            transitionState = MutableStateFlow(ObservableTransitionState.Idle(targetScene))
             underTest.setTransitionState(transitionState)
             assertThat(transitionProgress).isEqualTo(CommunalTransitionProgress.Idle(targetScene))
         }
@@ -640,7 +642,7 @@
             runCurrent()
             assertThat(isCommunalShowing()).isEqualTo(false)
 
-            underTest.onSceneChanged(CommunalSceneKey.Communal)
+            underTest.onSceneChanged(CommunalScenes.Communal)
 
             isCommunalShowing = collectLastValue(underTest.isCommunalShowing)
             runCurrent()
@@ -659,17 +661,17 @@
             assertThat(isCommunalShowing).isFalse()
 
             // Verify scene changes with the flag doesn't have any impact
-            sceneInteractor.changeScene(SceneKey.Communal, loggingReason = "")
+            sceneInteractor.changeScene(Scenes.Communal, loggingReason = "")
             runCurrent()
             assertThat(isCommunalShowing).isFalse()
 
             // Verify scene changes (without the flag) to communal sets the value to true
-            underTest.onSceneChanged(CommunalSceneKey.Communal)
+            underTest.onSceneChanged(CommunalScenes.Communal)
             runCurrent()
             assertThat(isCommunalShowing).isTrue()
 
             // Verify scene changes (without the flag) to blank sets the value back to false
-            underTest.onSceneChanged(CommunalSceneKey.Blank)
+            underTest.onSceneChanged(CommunalScenes.Blank)
             runCurrent()
             assertThat(isCommunalShowing).isFalse()
         }
@@ -685,17 +687,17 @@
             assertThat(isCommunalShowing).isFalse()
 
             // Verify scene changes without the flag doesn't have any impact
-            underTest.onSceneChanged(CommunalSceneKey.Communal)
+            underTest.onSceneChanged(CommunalScenes.Communal)
             runCurrent()
             assertThat(isCommunalShowing).isFalse()
 
             // Verify scene changes (with the flag) to communal sets the value to true
-            sceneInteractor.changeScene(SceneKey.Communal, loggingReason = "")
+            sceneInteractor.changeScene(Scenes.Communal, loggingReason = "")
             runCurrent()
             assertThat(isCommunalShowing).isTrue()
 
             // Verify scene changes (with the flag) to lockscreen sets the value to false
-            sceneInteractor.changeScene(SceneKey.Lockscreen, loggingReason = "")
+            sceneInteractor.changeScene(Scenes.Lockscreen, loggingReason = "")
             runCurrent()
             assertThat(isCommunalShowing).isFalse()
         }
@@ -704,8 +706,8 @@
     fun isIdleOnCommunal() =
         testScope.runTest {
             val transitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Idle(CommunalSceneKey.Blank)
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(CommunalScenes.Blank)
                 )
             communalRepository.setTransitionState(transitionState)
 
@@ -715,8 +717,7 @@
             assertThat(isIdleOnCommunal).isEqualTo(false)
 
             // Transition to communal.
-            transitionState.value =
-                ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal)
+            transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Communal)
             runCurrent()
 
             // isIdleOnCommunal is now true since we're on communal.
@@ -724,9 +725,9 @@
 
             // Start transition away from communal.
             transitionState.value =
-                ObservableCommunalTransitionState.Transition(
-                    fromScene = CommunalSceneKey.Communal,
-                    toScene = CommunalSceneKey.Blank,
+                ObservableTransitionState.Transition(
+                    fromScene = CommunalScenes.Communal,
+                    toScene = CommunalScenes.Blank,
                     progress = flowOf(0f),
                     isInitiatedByUserInput = false,
                     isUserInputOngoing = flowOf(false),
@@ -741,8 +742,8 @@
     fun isCommunalVisible() =
         testScope.runTest {
             val transitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Idle(CommunalSceneKey.Blank)
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(CommunalScenes.Blank)
                 )
             communalRepository.setTransitionState(transitionState)
 
@@ -752,9 +753,9 @@
 
             // Start transition to communal.
             transitionState.value =
-                ObservableCommunalTransitionState.Transition(
-                    fromScene = CommunalSceneKey.Blank,
-                    toScene = CommunalSceneKey.Communal,
+                ObservableTransitionState.Transition(
+                    fromScene = CommunalScenes.Blank,
+                    toScene = CommunalScenes.Communal,
                     progress = flowOf(0f),
                     isInitiatedByUserInput = false,
                     isUserInputOngoing = flowOf(false),
@@ -764,17 +765,16 @@
             assertThat(isCommunalVisible).isEqualTo(true)
 
             // Finish transition to communal
-            transitionState.value =
-                ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal)
+            transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Communal)
 
             // isCommunalVisible is true since we're on communal.
             assertThat(isCommunalVisible).isEqualTo(true)
 
             // Start transition away from communal.
             transitionState.value =
-                ObservableCommunalTransitionState.Transition(
-                    fromScene = CommunalSceneKey.Communal,
-                    toScene = CommunalSceneKey.Blank,
+                ObservableTransitionState.Transition(
+                    fromScene = CommunalScenes.Communal,
+                    toScene = CommunalScenes.Blank,
                     progress = flowOf(1.0f),
                     isInitiatedByUserInput = false,
                     isUserInputOngoing = flowOf(false),
@@ -831,6 +831,95 @@
             }
         }
 
+    @Test
+    fun widgetContent_containsDisabledWidgets_whenCategoryNotAllowed() =
+        testScope.runTest {
+            // Communal available, and tutorial completed.
+            keyguardRepository.setKeyguardShowing(true)
+            keyguardRepository.setKeyguardOccluded(false)
+            tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+            userRepository.setSelectedUserInfo(mainUser)
+
+            val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
+            userRepository.setUserInfos(userInfos)
+            userTracker.set(
+                userInfos = userInfos,
+                selectedUserIndex = 0,
+            )
+            runCurrent()
+
+            // Widgets available.
+            val widget1 =
+                createWidgetWithCategory(1, AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN)
+            val widget2 =
+                createWidgetWithCategory(2, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD)
+            val widget3 =
+                createWidgetWithCategory(3, AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX)
+            val widgets = listOf(widget1, widget2, widget3)
+            widgetRepository.setCommunalWidgets(widgets)
+
+            val widgetContent by collectLastValue(underTest.widgetContent)
+            kosmos.fakeSettings.putIntForUser(
+                CommunalSettingsRepositoryImpl.GLANCEABLE_HUB_CONTENT_SETTING,
+                AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD,
+                mainUser.id
+            )
+            runCurrent()
+
+            // Only the keyguard widget is enabled.
+            assertThat(widgetContent).hasSize(3)
+            assertThat(widgetContent!!.get(0))
+                .isInstanceOf(CommunalContentModel.WidgetContent.DisabledWidget::class.java)
+            assertThat(widgetContent!!.get(1))
+                .isInstanceOf(CommunalContentModel.WidgetContent.Widget::class.java)
+            assertThat(widgetContent!!.get(2))
+                .isInstanceOf(CommunalContentModel.WidgetContent.DisabledWidget::class.java)
+        }
+
+    @Test
+    fun widgetContent_allEnabled_whenCategoryAllowed() =
+        testScope.runTest {
+            // Communal available, and tutorial completed.
+            keyguardRepository.setKeyguardShowing(true)
+            keyguardRepository.setKeyguardOccluded(false)
+            tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+            userRepository.setSelectedUserInfo(mainUser)
+
+            val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
+            userRepository.setUserInfos(userInfos)
+            userTracker.set(
+                userInfos = userInfos,
+                selectedUserIndex = 0,
+            )
+            runCurrent()
+
+            // Widgets available.
+            val widget1 =
+                createWidgetWithCategory(1, AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN)
+            val widget2 =
+                createWidgetWithCategory(2, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD)
+            val widget3 =
+                createWidgetWithCategory(3, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD)
+            val widgets = listOf(widget1, widget2, widget3)
+            widgetRepository.setCommunalWidgets(widgets)
+
+            val widgetContent by collectLastValue(underTest.widgetContent)
+            kosmos.fakeSettings.putIntForUser(
+                CommunalSettingsRepositoryImpl.GLANCEABLE_HUB_CONTENT_SETTING,
+                AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD or
+                    AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,
+                mainUser.id
+            )
+            runCurrent()
+
+            // All widgets are enabled.
+            assertThat(widgetContent).hasSize(3)
+            widgetContent!!.forEach { model ->
+                assertThat(model)
+                    .isInstanceOf(CommunalContentModel.WidgetContent.Widget::class.java)
+            }
+        }
+
     private fun smartspaceTimer(id: String, timestamp: Long = 0L): SmartspaceTarget {
         val timer = mock(SmartspaceTarget::class.java)
         whenever(timer.smartspaceTargetId).thenReturn(id)
@@ -848,6 +937,17 @@
             whenever(this.providerInfo).thenReturn(providerInfo)
         }
 
+    private fun createWidgetWithCategory(
+        appWidgetId: Int,
+        category: Int
+    ): CommunalWidgetContentModel =
+        mock<CommunalWidgetContentModel> {
+            whenever(this.appWidgetId).thenReturn(appWidgetId)
+            val providerInfo = mock<AppWidgetProviderInfo>().apply { widgetCategory = category }
+            whenever(providerInfo.profile).thenReturn(UserHandle(MAIN_USER_INFO.id))
+            whenever(this.providerInfo).thenReturn(providerInfo)
+        }
+
     private companion object {
         val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
         val USER_INFO_WORK = UserInfo(10, "work", UserInfo.FLAG_PROFILE)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
index 8b78592..50b8da6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
@@ -25,7 +25,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.data.repository.FakeCommunalTutorialRepository
 import com.android.systemui.communal.data.repository.fakeCommunalTutorialRepository
-import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.flags.Flags
 import com.android.systemui.flags.fakeFeatureFlagsClassic
@@ -158,7 +158,7 @@
             kosmos.setCommunalAvailable(true)
             communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED)
 
-            communalInteractor.onSceneChanged(CommunalSceneKey.Blank)
+            communalInteractor.onSceneChanged(CommunalScenes.Blank)
 
             assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_NOT_STARTED)
         }
@@ -171,7 +171,7 @@
             goToCommunal()
             communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_STARTED)
 
-            communalInteractor.onSceneChanged(CommunalSceneKey.Blank)
+            communalInteractor.onSceneChanged(CommunalScenes.Blank)
 
             assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_COMPLETED)
         }
@@ -184,13 +184,13 @@
             goToCommunal()
             communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
 
-            communalInteractor.onSceneChanged(CommunalSceneKey.Blank)
+            communalInteractor.onSceneChanged(CommunalScenes.Blank)
 
             assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_COMPLETED)
         }
 
     private suspend fun goToCommunal() {
         kosmos.setCommunalAvailable(true)
-        communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+        communalInteractor.onSceneChanged(CommunalScenes.Communal)
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/log/CommunalLoggerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/log/CommunalLoggerStartableTest.kt
index 6b1b937..a51315b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/log/CommunalLoggerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/log/CommunalLoggerStartableTest.kt
@@ -18,13 +18,14 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.domain.interactor.communalInteractor
 import com.android.systemui.communal.shared.log.CommunalUiEvent
-import com.android.systemui.communal.shared.model.CommunalSceneKey
-import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
+import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.testKosmos
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -73,7 +74,7 @@
         testScope.runTest {
             // Transition state is default (non-communal)
             val transitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(idle(CommunalSceneKey.DEFAULT))
+                MutableStateFlow<ObservableTransitionState>(idle(CommunalScenes.Default))
             communalInteractor.setTransitionState(transitionState)
             runCurrent()
 
@@ -81,14 +82,14 @@
             verify(uiEventLogger, never()).log(any())
 
             // Start transition to communal
-            transitionState.value = transition(to = CommunalSceneKey.Communal)
+            transitionState.value = transition(to = CommunalScenes.Communal)
             runCurrent()
 
             // Verify UiEvent logged
             verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_ENTER_START)
 
             // Finish transition to communal
-            transitionState.value = idle(CommunalSceneKey.Communal)
+            transitionState.value = idle(CommunalScenes.Communal)
             runCurrent()
 
             // Verify UiEvent logged
@@ -101,7 +102,7 @@
         testScope.runTest {
             // Transition state is default (non-communal)
             val transitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(idle(CommunalSceneKey.DEFAULT))
+                MutableStateFlow<ObservableTransitionState>(idle(CommunalScenes.Default))
             communalInteractor.setTransitionState(transitionState)
             runCurrent()
 
@@ -109,14 +110,14 @@
             verify(uiEventLogger, never()).log(any())
 
             // Start transition to communal
-            transitionState.value = transition(to = CommunalSceneKey.Communal)
+            transitionState.value = transition(to = CommunalScenes.Communal)
             runCurrent()
 
             // Verify UiEvent logged
             verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_ENTER_START)
 
             // Cancel the transition
-            transitionState.value = idle(CommunalSceneKey.DEFAULT)
+            transitionState.value = idle(CommunalScenes.Default)
             runCurrent()
 
             // Verify UiEvent logged
@@ -132,7 +133,7 @@
         testScope.runTest {
             // Transition state is communal
             val transitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(idle(CommunalSceneKey.Communal))
+                MutableStateFlow<ObservableTransitionState>(idle(CommunalScenes.Communal))
             communalInteractor.setTransitionState(transitionState)
             runCurrent()
 
@@ -140,14 +141,14 @@
             verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_SHOWN)
 
             // Start transition from communal
-            transitionState.value = transition(from = CommunalSceneKey.Communal)
+            transitionState.value = transition(from = CommunalScenes.Communal)
             runCurrent()
 
             // Verify UiEvent logged
             verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_EXIT_START)
 
             // Finish transition to communal
-            transitionState.value = idle(CommunalSceneKey.DEFAULT)
+            transitionState.value = idle(CommunalScenes.Default)
             runCurrent()
 
             // Verify UiEvent logged
@@ -160,7 +161,7 @@
         testScope.runTest {
             // Transition state is communal
             val transitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(idle(CommunalSceneKey.Communal))
+                MutableStateFlow<ObservableTransitionState>(idle(CommunalScenes.Communal))
             communalInteractor.setTransitionState(transitionState)
             runCurrent()
 
@@ -168,14 +169,14 @@
             clearInvocations(uiEventLogger)
 
             // Start transition from communal
-            transitionState.value = transition(from = CommunalSceneKey.Communal)
+            transitionState.value = transition(from = CommunalScenes.Communal)
             runCurrent()
 
             // Verify UiEvent logged
             verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_EXIT_START)
 
             // Cancel the transition
-            transitionState.value = idle(CommunalSceneKey.Communal)
+            transitionState.value = idle(CommunalScenes.Communal)
             runCurrent()
 
             // Verify UiEvent logged
@@ -187,10 +188,10 @@
         }
 
     private fun transition(
-        from: CommunalSceneKey = CommunalSceneKey.DEFAULT,
-        to: CommunalSceneKey = CommunalSceneKey.DEFAULT,
-    ): ObservableCommunalTransitionState.Transition {
-        return ObservableCommunalTransitionState.Transition(
+        from: SceneKey = CommunalScenes.Default,
+        to: SceneKey = CommunalScenes.Default,
+    ): ObservableTransitionState.Transition {
+        return ObservableTransitionState.Transition(
             fromScene = from,
             toScene = to,
             progress = emptyFlow(),
@@ -199,7 +200,7 @@
         )
     }
 
-    private fun idle(sceneKey: CommunalSceneKey): ObservableCommunalTransitionState.Idle {
-        return ObservableCommunalTransitionState.Idle(sceneKey)
+    private fun idle(sceneKey: SceneKey): ObservableTransitionState.Idle {
+        return ObservableTransitionState.Idle(sceneKey)
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
index 5ee88cb..8e2e947 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
@@ -135,9 +135,9 @@
             // Only Widgets and CTA tile are shown.
             assertThat(communalContent?.size).isEqualTo(3)
             assertThat(communalContent?.get(0))
-                .isInstanceOf(CommunalContentModel.Widget::class.java)
+                .isInstanceOf(CommunalContentModel.WidgetContent::class.java)
             assertThat(communalContent?.get(1))
-                .isInstanceOf(CommunalContentModel.Widget::class.java)
+                .isInstanceOf(CommunalContentModel.WidgetContent::class.java)
             assertThat(communalContent?.get(2))
                 .isInstanceOf(CommunalContentModel.CtaTileInEditMode::class.java)
         }
@@ -181,9 +181,9 @@
             // Widgets and CTA tile are shown.
             assertThat(communalContent?.size).isEqualTo(3)
             assertThat(communalContent?.get(0))
-                .isInstanceOf(CommunalContentModel.Widget::class.java)
+                .isInstanceOf(CommunalContentModel.WidgetContent::class.java)
             assertThat(communalContent?.get(1))
-                .isInstanceOf(CommunalContentModel.Widget::class.java)
+                .isInstanceOf(CommunalContentModel.WidgetContent::class.java)
             assertThat(communalContent?.get(2))
                 .isInstanceOf(CommunalContentModel.CtaTileInEditMode::class.java)
 
@@ -192,7 +192,8 @@
             // Only one widget and CTA tile remain.
             assertThat(communalContent?.size).isEqualTo(2)
             val item = communalContent?.get(0)
-            val appWidgetId = if (item is CommunalContentModel.Widget) item.appWidgetId else null
+            val appWidgetId =
+                if (item is CommunalContentModel.WidgetContent) item.appWidgetId else null
             assertThat(appWidgetId).isEqualTo(widgets.get(1).appWidgetId)
             assertThat(communalContent?.get(1))
                 .isInstanceOf(CommunalContentModel.CtaTileInEditMode::class.java)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index 1e523dd..8f802b8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -39,6 +39,7 @@
 import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
 import com.android.systemui.communal.ui.viewmodel.CommunalViewModel.Companion.POPUP_AUTO_HIDE_TIMEOUT_MS
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
 import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED
 import com.android.systemui.flags.fakeFeatureFlagsClassic
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -113,6 +114,7 @@
                 kosmos.communalInteractor,
                 kosmos.communalTutorialInteractor,
                 kosmos.shadeInteractor,
+                kosmos.deviceEntryInteractor,
                 mediaHost,
                 logcatLogBuffer("CommunalViewModelTest"),
             )
@@ -184,9 +186,9 @@
                 .isInstanceOf(CommunalContentModel.Smartspace::class.java)
             assertThat(communalContent?.get(1)).isInstanceOf(CommunalContentModel.Umo::class.java)
             assertThat(communalContent?.get(2))
-                .isInstanceOf(CommunalContentModel.Widget::class.java)
+                .isInstanceOf(CommunalContentModel.WidgetContent::class.java)
             assertThat(communalContent?.get(3))
-                .isInstanceOf(CommunalContentModel.Widget::class.java)
+                .isInstanceOf(CommunalContentModel.WidgetContent::class.java)
             assertThat(communalContent?.get(4))
                 .isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java)
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt
index 12611cb..88f5e1b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt
@@ -17,8 +17,10 @@
 package com.android.systemui.communal.widgets
 
 import android.appwidget.AppWidgetManager
+import android.appwidget.AppWidgetProviderInfo
 import android.content.ComponentName
 import android.content.pm.UserInfo
+import android.os.Bundle
 import android.os.UserHandle
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -33,8 +35,8 @@
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import com.android.systemui.user.domain.interactor.selectedUserInteractor
 import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.nullable
 import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
 import com.google.common.truth.Truth.assertThat
 import java.util.Optional
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -43,6 +45,7 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
@@ -91,7 +94,7 @@
                         any<Int>(),
                         any<UserHandle>(),
                         any<ComponentName>(),
-                        nullable()
+                        any<Bundle>(),
                     )
                 )
                 .thenReturn(true)
@@ -100,8 +103,14 @@
             val result = underTest.allocateIdAndBindWidget(provider)
 
             verify(appWidgetHost).allocateAppWidgetId()
-            verify(appWidgetManager).bindAppWidgetIdIfAllowed(widgetId, user, provider, null)
+            val bundle =
+                withArgCaptor<Bundle> {
+                    verify(appWidgetManager)
+                        .bindAppWidgetIdIfAllowed(eq(widgetId), eq(user), eq(provider), capture())
+                }
             assertThat(result).isEqualTo(widgetId)
+            assertThat(bundle.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY))
+                .isEqualTo(AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD)
         }
 
     @Test
@@ -117,7 +126,7 @@
                         any<Int>(),
                         any<UserHandle>(),
                         any<ComponentName>(),
-                        nullable()
+                        any<Bundle>()
                     )
                 )
                 .thenReturn(true)
@@ -126,8 +135,14 @@
             val result = underTest.allocateIdAndBindWidget(provider, user)
 
             verify(appWidgetHost).allocateAppWidgetId()
-            verify(appWidgetManager).bindAppWidgetIdIfAllowed(widgetId, user, provider, null)
+            val bundle =
+                withArgCaptor<Bundle> {
+                    verify(appWidgetManager)
+                        .bindAppWidgetIdIfAllowed(eq(widgetId), eq(user), eq(provider), capture())
+                }
             assertThat(result).isEqualTo(widgetId)
+            assertThat(bundle.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY))
+                .isEqualTo(AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD)
         }
 
     @Test
@@ -144,14 +159,15 @@
                         any<Int>(),
                         any<UserHandle>(),
                         any<ComponentName>(),
-                        nullable()
+                        any<Bundle>()
                     )
                 )
                 .thenReturn(false)
             val result = underTest.allocateIdAndBindWidget(provider, user)
 
             verify(appWidgetHost).allocateAppWidgetId()
-            verify(appWidgetManager).bindAppWidgetIdIfAllowed(widgetId, user, provider, null)
+            verify(appWidgetManager)
+                .bindAppWidgetIdIfAllowed(eq(widgetId), eq(user), eq(provider), any())
             verify(appWidgetHost).deleteAppWidgetId(widgetId)
             assertThat(result).isNull()
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index b611e0a..36919d0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -1052,32 +1052,6 @@
             biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(true)
             faceAuthenticateIsCalled()
         }
-    @Test
-    fun authFailedCallAfterAuthLockedOutErrorShouldBeIgnored() =
-        testScope.runTest {
-            initCollectors()
-            allPreconditionsToRunFaceAuthAreTrue()
-            runCurrent()
-            assertThat(canFaceAuthRun()).isTrue()
-
-            underTest.requestAuthenticate(FACE_AUTH_TRIGGERED_NOTIFICATION_PANEL_CLICKED, false)
-            runCurrent()
-
-            faceAuthenticateIsCalled()
-            authenticationCallback.value.onAuthenticationError(
-                FACE_ERROR_LOCKOUT_PERMANENT,
-                "Too many attempts, face not available"
-            )
-
-            val lockoutError = authStatus() as ErrorFaceAuthenticationStatus
-            assertThat(lockedOut()).isTrue()
-            assertThat(lockoutError.isLockoutError()).isTrue()
-
-            authenticationCallback.value.onAuthenticationFailed()
-            runCurrent()
-
-            assertThat(authStatus()).isEqualTo(lockoutError)
-        }
 
     private suspend fun TestScope.testGatingCheckForFaceAuth(
         gatingCheckModifier: suspend () -> Unit
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
index 98719dd3..4f44705 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
@@ -18,6 +18,7 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
 import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
@@ -31,7 +32,7 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -120,7 +121,7 @@
         testScope.runTest {
             val isDeviceEntered by collectLastValue(underTest.isDeviceEntered)
             setupSwipeDeviceEntryMethod()
-            switchToScene(SceneKey.Lockscreen)
+            switchToScene(Scenes.Lockscreen)
 
             assertThat(isDeviceEntered).isFalse()
         }
@@ -130,9 +131,9 @@
         testScope.runTest {
             val isDeviceEntered by collectLastValue(underTest.isDeviceEntered)
             setupSwipeDeviceEntryMethod()
-            switchToScene(SceneKey.Lockscreen)
+            switchToScene(Scenes.Lockscreen)
             runCurrent()
-            switchToScene(SceneKey.Shade)
+            switchToScene(Scenes.Shade)
 
             assertThat(isDeviceEntered).isFalse()
         }
@@ -142,9 +143,9 @@
         testScope.runTest {
             val isDeviceEntered by collectLastValue(underTest.isDeviceEntered)
             setupSwipeDeviceEntryMethod()
-            switchToScene(SceneKey.Lockscreen)
+            switchToScene(Scenes.Lockscreen)
             runCurrent()
-            switchToScene(SceneKey.Gone)
+            switchToScene(Scenes.Gone)
 
             assertThat(isDeviceEntered).isTrue()
         }
@@ -154,11 +155,11 @@
         testScope.runTest {
             val isDeviceEntered by collectLastValue(underTest.isDeviceEntered)
             setupSwipeDeviceEntryMethod()
-            switchToScene(SceneKey.Lockscreen)
+            switchToScene(Scenes.Lockscreen)
             runCurrent()
-            switchToScene(SceneKey.Gone)
+            switchToScene(Scenes.Gone)
             runCurrent()
-            switchToScene(SceneKey.Shade)
+            switchToScene(Scenes.Shade)
 
             assertThat(isDeviceEntered).isTrue()
         }
@@ -170,9 +171,9 @@
                 AuthenticationMethodModel.Pattern
             )
             kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true)
-            switchToScene(SceneKey.Lockscreen)
+            switchToScene(Scenes.Lockscreen)
             runCurrent()
-            switchToScene(SceneKey.Bouncer)
+            switchToScene(Scenes.Bouncer)
 
             val isDeviceEntered by collectLastValue(underTest.isDeviceEntered)
             assertThat(isDeviceEntered).isFalse()
@@ -182,7 +183,7 @@
     fun canSwipeToEnter_onLockscreenWithSwipe_isTrue() =
         testScope.runTest {
             setupSwipeDeviceEntryMethod()
-            switchToScene(SceneKey.Lockscreen)
+            switchToScene(Scenes.Lockscreen)
 
             val canSwipeToEnter by collectLastValue(underTest.canSwipeToEnter)
             assertThat(canSwipeToEnter).isTrue()
@@ -195,7 +196,7 @@
                 AuthenticationMethodModel.Pin
             )
             kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true)
-            switchToScene(SceneKey.Lockscreen)
+            switchToScene(Scenes.Lockscreen)
 
             val canSwipeToEnter by collectLastValue(underTest.canSwipeToEnter)
             assertThat(canSwipeToEnter).isFalse()
@@ -205,9 +206,9 @@
     fun canSwipeToEnter_afterLockscreenDismissedInSwipeMode_isFalse() =
         testScope.runTest {
             setupSwipeDeviceEntryMethod()
-            switchToScene(SceneKey.Lockscreen)
+            switchToScene(Scenes.Lockscreen)
             runCurrent()
-            switchToScene(SceneKey.Gone)
+            switchToScene(Scenes.Gone)
 
             val canSwipeToEnter by collectLastValue(underTest.canSwipeToEnter)
             assertThat(canSwipeToEnter).isFalse()
@@ -225,7 +226,7 @@
             kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
                 AuthenticationMethodModel.Password
             )
-            switchToScene(SceneKey.Lockscreen)
+            switchToScene(Scenes.Lockscreen)
             assertThat(canSwipeToEnter).isFalse()
 
             trustRepository.setCurrentUserTrusted(true)
@@ -242,7 +243,7 @@
             kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
                 AuthenticationMethodModel.Password
             )
-            switchToScene(SceneKey.Lockscreen)
+            switchToScene(Scenes.Lockscreen)
             assertThat(canSwipeToEnter).isFalse()
 
             faceAuthRepository.isAuthenticated.value = true
@@ -311,8 +312,8 @@
     fun showOrUnlockDevice_notLocked_switchesToGoneScene() =
         testScope.runTest {
             val currentScene by collectLastValue(sceneInteractor.currentScene)
-            switchToScene(SceneKey.Lockscreen)
-            assertThat(currentScene).isEqualTo(SceneKey.Lockscreen)
+            switchToScene(Scenes.Lockscreen)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
 
             kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
                 AuthenticationMethodModel.Pin
@@ -322,15 +323,15 @@
 
             underTest.attemptDeviceEntry()
 
-            assertThat(currentScene).isEqualTo(SceneKey.Gone)
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
         }
 
     @Test
     fun showOrUnlockDevice_authMethodNotSecure_switchesToGoneScene() =
         testScope.runTest {
             val currentScene by collectLastValue(sceneInteractor.currentScene)
-            switchToScene(SceneKey.Lockscreen)
-            assertThat(currentScene).isEqualTo(SceneKey.Lockscreen)
+            switchToScene(Scenes.Lockscreen)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
 
             kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
                 AuthenticationMethodModel.None
@@ -339,15 +340,15 @@
 
             underTest.attemptDeviceEntry()
 
-            assertThat(currentScene).isEqualTo(SceneKey.Gone)
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
         }
 
     @Test
     fun showOrUnlockDevice_authMethodSwipe_switchesToGoneScene() =
         testScope.runTest {
             val currentScene by collectLastValue(sceneInteractor.currentScene)
-            switchToScene(SceneKey.Lockscreen)
-            assertThat(currentScene).isEqualTo(SceneKey.Lockscreen)
+            switchToScene(Scenes.Lockscreen)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
 
             kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true)
             kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
@@ -357,7 +358,7 @@
 
             underTest.attemptDeviceEntry()
 
-            assertThat(currentScene).isEqualTo(SceneKey.Gone)
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
         }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
index a6715df..c670506 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
@@ -11,7 +11,6 @@
 import com.android.systemui.dreams.ui.viewmodel.DreamOverlayViewModel
 import com.android.systemui.log.core.FakeLogBuffer
 import com.android.systemui.statusbar.BlurUtils
-import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
@@ -46,7 +45,6 @@
     @Mock private lateinit var hostViewController: ComplicationHostViewController
     @Mock private lateinit var statusBarViewController: DreamOverlayStatusBarViewController
     @Mock private lateinit var stateController: DreamOverlayStateController
-    @Mock private lateinit var configController: ConfigurationController
     @Mock private lateinit var transitionViewModel: DreamOverlayViewModel
     private val logBuffer = FakeLogBuffer.Factory.create()
     private lateinit var controller: DreamOverlayAnimationsController
@@ -62,7 +60,6 @@
                 stateController,
                 DREAM_BLUR_RADIUS,
                 transitionViewModel,
-                configController,
                 DREAM_IN_BLUR_ANIMATION_DURATION,
                 DREAM_IN_COMPLICATIONS_ANIMATION_DURATION,
                 DREAM_IN_TRANSLATION_Y_DISTANCE,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
index 558e7e6..3a28471 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
@@ -33,6 +33,7 @@
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.filterIsInstance
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runCurrent
@@ -215,6 +216,39 @@
         }
 
     @Test
+    fun onFingerprintFailed_failedAuthenticationStatusWithOtherStatuses() =
+        testScope.runTest {
+            val failStatus by
+                collectLastValue(
+                    underTest.authenticationStatus.filterIsInstance<
+                        FailFingerprintAuthenticationStatus
+                    >()
+                )
+            runCurrent()
+
+            verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture())
+            updateMonitorCallback.value.onBiometricAcquired(
+                BiometricSourceType.FINGERPRINT,
+                /* acquireInfo */ 0,
+            )
+            updateMonitorCallback.value.onBiometricAuthFailed(
+                BiometricSourceType.FINGERPRINT,
+            )
+            updateMonitorCallback.value.onBiometricHelp(
+                /* msgId */ 7,
+                /* errString */ "Not recognized.",
+                BiometricSourceType.FINGERPRINT,
+            )
+            updateMonitorCallback.value.onBiometricError(
+                /* msgId */ 7,
+                /* errString */ "Too many attempts.",
+                BiometricSourceType.FINGERPRINT,
+            )
+
+            assertThat(failStatus).isNotNull()
+        }
+
+    @Test
     fun onFingerprintError_errorAuthenticationStatus() =
         testScope.runTest {
             val authenticationStatus by collectLastValue(underTest.authenticationStatus)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index ef2b6f0..f9ec3d1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -20,6 +20,7 @@
 import android.app.StatusBarManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
@@ -35,8 +36,7 @@
 import com.android.systemui.power.domain.interactor.PowerInteractorFactory
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.data.repository.FakeShadeRepository
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
@@ -64,7 +64,7 @@
     private val shadeRepository = FakeShadeRepository()
     private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
     private val transitionState: MutableStateFlow<ObservableTransitionState> =
-        MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Gone))
+        MutableStateFlow(ObservableTransitionState.Idle(Scenes.Gone))
 
     private val underTest by lazy {
         KeyguardInteractor(
@@ -250,8 +250,8 @@
             underTest.setAnimateDozingTransitions(true)
             transitionState.value =
                 ObservableTransitionState.Transition(
-                    fromScene = SceneKey.Gone,
-                    toScene = SceneKey.Lockscreen,
+                    fromScene = Scenes.Gone,
+                    toScene = Scenes.Lockscreen,
                     progress = flowOf(0f),
                     isInitiatedByUserInput = false,
                     isUserInputOngoing = flowOf(false),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
index 3484025..cd4db2f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
@@ -79,34 +79,66 @@
     }
 
     @Test
-    fun dozeAmountTransitionTest() = runTest {
-        val dozeAmountSteps by collectValues(underTest.dozeAmountTransition)
+    fun dozeAmountTransitionTest_AodToFromLockscreen() =
+        testScope.runTest {
+            val dozeAmountSteps by collectValues(underTest.dozeAmountTransition)
 
-        val steps = mutableListOf<TransitionStep>()
+            val steps = mutableListOf<TransitionStep>()
 
-        steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED))
-        steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING))
-        steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED))
-        steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED))
-        steps.add(TransitionStep(LOCKSCREEN, AOD, 0.8f, RUNNING))
-        steps.add(TransitionStep(LOCKSCREEN, AOD, 0.9f, RUNNING))
-        steps.add(TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED))
+            steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED))
+            steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING))
+            steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED))
+            steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED))
+            steps.add(TransitionStep(LOCKSCREEN, AOD, 0.8f, RUNNING))
+            steps.add(TransitionStep(LOCKSCREEN, AOD, 0.9f, RUNNING))
+            steps.add(TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED))
 
-        steps.forEach {
-            repository.sendTransitionStep(it)
-            runCurrent()
+            steps.forEach {
+                repository.sendTransitionStep(it)
+                runCurrent()
+            }
+
+            assertThat(dozeAmountSteps.subList(0, 3))
+                .isEqualTo(
+                    listOf(
+                        steps[0].copy(value = 1f - steps[0].value),
+                        steps[1].copy(value = 1f - steps[1].value),
+                        steps[2].copy(value = 1f - steps[2].value),
+                    )
+                )
+            assertThat(dozeAmountSteps.subList(3, 7)).isEqualTo(steps.subList(3, 7))
         }
 
-        assertThat(dozeAmountSteps.subList(0, 3))
-            .isEqualTo(
-                listOf(
-                    steps[0].copy(value = 1f - steps[0].value),
-                    steps[1].copy(value = 1f - steps[1].value),
-                    steps[2].copy(value = 1f - steps[2].value),
+    @Test
+    fun dozeAmountTransitionTest_AodToFromGone() =
+        testScope.runTest {
+            val dozeAmountSteps by collectValues(underTest.dozeAmountTransition)
+
+            val steps = mutableListOf<TransitionStep>()
+
+            steps.add(TransitionStep(AOD, GONE, 0f, STARTED))
+            steps.add(TransitionStep(AOD, GONE, 0.3f, RUNNING))
+            steps.add(TransitionStep(AOD, GONE, 1f, FINISHED))
+            steps.add(TransitionStep(GONE, AOD, 0f, STARTED))
+            steps.add(TransitionStep(GONE, AOD, 0.1f, RUNNING))
+            steps.add(TransitionStep(GONE, AOD, 0.3f, RUNNING))
+            steps.add(TransitionStep(GONE, AOD, 1f, FINISHED))
+
+            steps.forEach {
+                repository.sendTransitionStep(it)
+                runCurrent()
+            }
+
+            assertThat(dozeAmountSteps.subList(0, 3))
+                .isEqualTo(
+                    listOf(
+                        steps[0].copy(value = 1f - steps[0].value),
+                        steps[1].copy(value = 1f - steps[1].value),
+                        steps[2].copy(value = 1f - steps[2].value),
+                    )
                 )
-            )
-        assertThat(dozeAmountSteps.subList(3, 7)).isEqualTo(steps.subList(3, 7))
-    }
+            assertThat(dozeAmountSteps.subList(3, 7)).isEqualTo(steps.subList(3, 7))
+        }
 
     @Test
     fun finishedKeyguardStateTests() =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt
index 199ffa6..3f6e229 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt
@@ -19,15 +19,15 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
 import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
 import com.android.systemui.biometrics.shared.model.FingerprintSensorType
 import com.android.systemui.biometrics.shared.model.SensorStrength
 import com.android.systemui.coroutines.collectValues
-import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
 import com.android.systemui.keyguard.shared.model.TransitionState
@@ -63,7 +63,7 @@
     }
 
     @Test
-    fun deviceEntryParentViewAppear() =
+    fun deviceEntryParentViewAppear_udfpsEnrolledAndEnabled() =
         testScope.runTest {
             fingerprintPropertyRepository.setProperties(
                 sensorId = 0,
@@ -90,6 +90,33 @@
         }
 
     @Test
+    fun deviceEntryParentViewDisappear_udfpsNotEnrolledAndEnabled() =
+        testScope.runTest {
+            fingerprintPropertyRepository.setProperties(
+                sensorId = 0,
+                strength = SensorStrength.STRONG,
+                sensorType = FingerprintSensorType.UDFPS_OPTICAL,
+                sensorLocations = emptyMap(),
+            )
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(0f) }
+        }
+
+    @Test
     fun deviceEntryBackgroundViewDisappear() =
         testScope.runTest {
             val values by collectValues(underTest.deviceEntryBackgroundViewAlpha)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelTest.kt
new file mode 100644
index 0000000..f8a6fc7
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelTest.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AlternateBouncerToDozingTransitionViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+    private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
+    private lateinit var underTest: AlternateBouncerToDozingTransitionViewModel
+
+    @Before
+    fun setUp() {
+        keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+        fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
+        biometricSettingsRepository = kosmos.biometricSettingsRepository
+        underTest = kosmos.alternateBouncerToDozingTransitionViewModel
+    }
+
+    @Test
+    fun deviceEntryParentViewAppear_udfpsEnrolledAndEnabled() =
+        testScope.runTest {
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(1f) }
+        }
+
+    @Test
+    fun deviceEntryParentViewDisappear_udfpsNotEnrolledAndEnabled() =
+        testScope.runTest {
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(0f) }
+        }
+
+    @Test
+    fun deviceEntryBackgroundViewDisappear() =
+        testScope.runTest {
+            val values by collectValues(underTest.deviceEntryBackgroundViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(0f) }
+        }
+
+    private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep {
+        return TransitionStep(
+            from = KeyguardState.ALTERNATE_BOUNCER,
+            to = KeyguardState.DOZING,
+            value = value,
+            transitionState = state,
+            ownerName = "AlternateBouncerToDozingTransitionViewModelTest"
+        )
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt
similarity index 82%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt
index 4c972e9..a3371d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt
@@ -42,6 +42,25 @@
     val underTest = kosmos.aodToGoneTransitionViewModel
 
     @Test
+    fun lockscreenAlpha() =
+        testScope.runTest {
+            val viewState = ViewStateAccessor(alpha = { 0.5f })
+            val alpha by collectValues(underTest.lockscreenAlpha(viewState))
+
+            repository.sendTransitionSteps(
+                from = KeyguardState.AOD,
+                to = KeyguardState.GONE,
+                testScope
+            )
+
+            assertThat(alpha[0]).isEqualTo(0.5f)
+            // Fades out just prior to halfway
+            assertThat(alpha[1]).isEqualTo(0f)
+            // Must finish at 0
+            assertThat(alpha[2]).isEqualTo(0f)
+        }
+
+    @Test
     fun deviceEntryParentViewHides() =
         testScope.runTest {
             val deviceEntryParentViewAlpha by collectValues(underTest.deviceEntryParentViewAlpha)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelTest.kt
new file mode 100644
index 0000000..79671b8
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelTest.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DozingToGoneTransitionViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var underTest: DozingToGoneTransitionViewModel
+
+    @Before
+    fun setUp() {
+        keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+        underTest = kosmos.dozingToGoneTransitionViewModel
+    }
+
+    @Test
+    fun lockscreenAlpha() =
+        testScope.runTest {
+            val viewState = ViewStateAccessor(alpha = { 0.6f })
+            val alpha by collectValues(underTest.lockscreenAlpha(viewState))
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.DOZING,
+                to = KeyguardState.GONE,
+                testScope
+            )
+
+            assertThat(alpha[0]).isEqualTo(0.6f)
+            // Fades out just prior to halfway
+            assertThat(alpha[1]).isEqualTo(0f)
+            // Must finish at 0
+            assertThat(alpha[2]).isEqualTo(0f)
+        }
+
+    @Test
+    fun deviceEntryParentViewDisappear() =
+        testScope.runTest {
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(0f) }
+        }
+
+    private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep {
+        return TransitionStep(
+            from = KeyguardState.DOZING,
+            to = KeyguardState.GONE,
+            value = value,
+            transitionState = state,
+            ownerName = "DozingToGoneTransitionViewModelTest"
+        )
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt
similarity index 81%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt
index 471029b..4a10d80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt
@@ -54,6 +54,19 @@
             deviceEntryParentViewAlpha.forEach { assertThat(it).isEqualTo(1f) }
         }
 
+    @Test
+    fun deviceEntryBackgroundViewShows() =
+        testScope.runTest {
+            val backgroundViewAlpha by collectValues(underTest.deviceEntryBackgroundViewAlpha)
+            repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+            repository.sendTransitionStep(step(0.1f))
+            repository.sendTransitionStep(step(0.3f))
+            repository.sendTransitionStep(step(0.5f))
+            repository.sendTransitionStep(step(0.6f))
+            repository.sendTransitionStep(step(1f))
+            backgroundViewAlpha.forEach { assertThat(it).isEqualTo(1f) }
+        }
+
     private fun step(
         value: Float,
         state: TransitionState = TransitionState.RUNNING
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelTest.kt
new file mode 100644
index 0000000..bf71bec
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelTest.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DozingToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var underTest: DozingToPrimaryBouncerTransitionViewModel
+
+    @Before
+    fun setUp() {
+        keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+        underTest = kosmos.dozingToPrimaryBouncerTransitionViewModel
+    }
+
+    @Test
+    fun deviceEntryParentViewDisappear() =
+        testScope.runTest {
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(0f) }
+        }
+
+    private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep {
+        return TransitionStep(
+            from = KeyguardState.DOZING,
+            to = KeyguardState.PRIMARY_BOUNCER,
+            value = value,
+            transitionState = state,
+            ownerName = "DozingToPrimaryBouncerTransitionViewModelTest"
+        )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt
index 4defe8a..aba21c9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt
@@ -19,12 +19,14 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
 import com.android.systemui.testKosmos
 import com.google.common.collect.Range
 import com.google.common.truth.Truth.assertThat
@@ -38,6 +40,7 @@
     val kosmos = testKosmos()
     val testScope = kosmos.testScope
 
+    val configurationRepository by lazy { kosmos.fakeConfigurationRepository }
     val underTest by lazy { kosmos.dreamingToGlanceableHubTransitionViewModel }
 
     @Test
@@ -66,7 +69,12 @@
     @Test
     fun dreamOverlayTranslationX() =
         testScope.runTest {
-            val values by collectValues(underTest.dreamOverlayTranslationX(100))
+            configurationRepository.setDimensionPixelSize(
+                R.dimen.dreaming_to_hub_transition_dream_overlay_translation_x,
+                -100
+            )
+
+            val values by collectValues(underTest.dreamOverlayTranslationX)
             assertThat(values).isEmpty()
 
             kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelTest.kt
new file mode 100644
index 0000000..11890c7
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelTest.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.testKosmos
+import com.google.common.collect.Range
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class GlanceableHubToDreamingTransitionViewModelTest : SysuiTestCase() {
+    val kosmos = testKosmos()
+    val testScope = kosmos.testScope
+
+    val configurationRepository by lazy { kosmos.fakeConfigurationRepository }
+    val underTest by lazy { kosmos.glanceableHubToDreamingTransitionViewModel }
+
+    @Test
+    fun dreamOverlayAlpha() =
+        testScope.runTest {
+            val values by collectValues(underTest.dreamOverlayAlpha)
+            assertThat(values).isEmpty()
+
+            kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    // Should start running here...
+                    step(0.1f),
+                    step(0.5f),
+                    // Up to here...
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            assertThat(values).hasSize(2)
+            values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
+        }
+
+    @Test
+    fun dreamOverlayTranslationX() =
+        testScope.runTest {
+            configurationRepository.setDimensionPixelSize(
+                R.dimen.hub_to_dreaming_transition_dream_overlay_translation_x,
+                100
+            )
+
+            val values by collectValues(underTest.dreamOverlayTranslationX)
+            assertThat(values).isEmpty()
+
+            kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0.3f),
+                    step(0.6f),
+                ),
+                testScope,
+            )
+
+            assertThat(values).hasSize(3)
+            values.forEach { assertThat(it).isIn(Range.closed(-100f, 0f)) }
+        }
+
+    private fun step(
+        value: Float,
+        state: TransitionState = TransitionState.RUNNING
+    ): TransitionStep {
+        return TransitionStep(
+            from = KeyguardState.GLANCEABLE_HUB,
+            to = KeyguardState.DREAMING,
+            value = value,
+            transitionState = state,
+            ownerName = GlanceableHubToDreamingTransitionViewModelTest::class.java.simpleName
+        )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelTest.kt
new file mode 100644
index 0000000..59a6ce7
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelTest.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.fakeFingerprintPropertyRepository
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class GoneToDozingTransitionViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+    private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
+    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var underTest: GoneToDozingTransitionViewModel
+
+    @Before
+    fun setUp() {
+        fingerprintPropertyRepository = kosmos.fakeFingerprintPropertyRepository
+        biometricSettingsRepository = kosmos.fakeBiometricSettingsRepository
+        keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+        underTest = kosmos.goneToDozingTransitionViewModel
+    }
+
+    @Test
+    fun deviceEntryParentViewAppear_udfpsEnrolledAndEnabled() =
+        testScope.runTest {
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(1f) }
+        }
+
+    @Test
+    fun deviceEntryParentViewDisappear_noUdfpsEnrolled_noUpdates() =
+        testScope.runTest {
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isNull() }
+        }
+
+    private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep {
+        return TransitionStep(
+            from = KeyguardState.GONE,
+            to = KeyguardState.DOZING,
+            value = value,
+            transitionState = state,
+            ownerName = "GoneToDozingTransitionViewModelTest"
+        )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index 503fd34..979d504 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -22,12 +22,12 @@
 import android.view.View
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.Flags as AConfigFlags
 import com.android.systemui.Flags.FLAG_NEW_AOD_TRANSITION
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.data.repository.communalRepository
-import com.android.systemui.communal.shared.model.CommunalSceneKey
-import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
+import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
 import com.android.systemui.flags.Flags
@@ -262,7 +262,7 @@
 
             // Hub transition state is idle with hub open.
             communalRepository.setTransitionState(
-                flowOf(ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal))
+                flowOf(ObservableTransitionState.Idle(CommunalScenes.Communal))
             )
             runCurrent()
 
@@ -328,4 +328,42 @@
             shadeRepository.setQsExpansion(0.5f)
             assertThat(alpha).isEqualTo(0f)
         }
+
+    @Test
+    fun alpha_idleOnOccluded_isZero() =
+        testScope.runTest {
+            val alpha by collectLastValue(underTest.alpha(viewState))
+            assertThat(alpha).isEqualTo(1f)
+
+            // Go to OCCLUDED state
+            keyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.LOCKSCREEN,
+                to = KeyguardState.OCCLUDED,
+                testScope = testScope,
+            )
+            assertThat(alpha).isEqualTo(0f)
+
+            // Try pulling down shade and ensure the value doesn't change
+            shadeRepository.setQsExpansion(0.5f)
+            assertThat(alpha).isEqualTo(0f)
+        }
+
+    @Test
+    fun alpha_idleOnGone_isZero() =
+        testScope.runTest {
+            val alpha by collectLastValue(underTest.alpha(viewState))
+            assertThat(alpha).isEqualTo(1f)
+
+            // Go to GONE state
+            keyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.LOCKSCREEN,
+                to = KeyguardState.GONE,
+                testScope = testScope,
+            )
+            assertThat(alpha).isEqualTo(0f)
+
+            // Try pulling down shade and ensure the value doesn't change
+            shadeRepository.setQsExpansion(0.5f)
+            assertThat(alpha).isEqualTo(0f)
+        }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
index 0b80ff8..ad1cef1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
@@ -36,7 +37,6 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
-@android.platform.test.annotations.EnabledOnRavenwood
 class LockscreenContentViewModelTest : SysuiTestCase() {
 
     private val kosmos: Kosmos = testKosmos()
@@ -47,6 +47,7 @@
     fun setup() {
         with(kosmos) {
             fakeFeatureFlagsClassic.set(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED, true)
+            overrideResource(R.bool.config_use_split_notification_shade, false)
             underTest = lockscreenContentViewModel
         }
     }
@@ -88,11 +89,21 @@
         }
 
     @Test
+    fun areNotificationsVisible_splitShadeTrue_true() =
+        with(kosmos) {
+            testScope.runTest {
+                overrideResource(R.bool.config_use_split_notification_shade, true)
+                kosmos.fakeKeyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE)
+
+                assertThat(underTest.areNotificationsVisible(context.resources)).isTrue()
+            }
+        }
+    @Test
     fun areNotificationsVisible_withSmallClock_true() =
         with(kosmos) {
             testScope.runTest {
                 kosmos.fakeKeyguardClockRepository.setClockSize(KeyguardClockSwitch.SMALL)
-                assertThat(underTest.areNotificationsVisible).isTrue()
+                assertThat(underTest.areNotificationsVisible(context.resources)).isTrue()
             }
         }
 
@@ -101,7 +112,7 @@
         with(kosmos) {
             testScope.runTest {
                 kosmos.fakeKeyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE)
-                assertThat(underTest.areNotificationsVisible).isFalse()
+                assertThat(underTest.areNotificationsVisible(context.resources)).isFalse()
             }
         }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
index 3104842..9ff76be 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
@@ -32,7 +32,7 @@
 import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModel
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.mock
@@ -62,9 +62,9 @@
             )
             kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true)
             kosmos.fakeDeviceEntryRepository.setUnlocked(true)
-            sceneInteractor.changeScene(SceneKey.Lockscreen, "reason")
+            sceneInteractor.changeScene(Scenes.Lockscreen, "reason")
 
-            assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
+            assertThat(upTransitionSceneKey).isEqualTo(Scenes.Gone)
         }
 
     @Test
@@ -75,9 +75,9 @@
                 AuthenticationMethodModel.Pin
             )
             kosmos.fakeDeviceEntryRepository.setUnlocked(false)
-            sceneInteractor.changeScene(SceneKey.Lockscreen, "reason")
+            sceneInteractor.changeScene(Scenes.Lockscreen, "reason")
 
-            assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Bouncer)
+            assertThat(upTransitionSceneKey).isEqualTo(Scenes.Bouncer)
         }
 
     @EnableFlags(FLAG_COMMUNAL_HUB)
@@ -89,7 +89,7 @@
 
             kosmos.setCommunalAvailable(true)
             runCurrent()
-            assertThat(leftDestinationSceneKey).isEqualTo(SceneKey.Communal)
+            assertThat(leftDestinationSceneKey).isEqualTo(Scenes.Communal)
         }
 
     private fun createLockscreenSceneViewModel(): LockscreenSceneViewModel {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt
index e139466..bef9515 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt
@@ -36,10 +36,10 @@
 import com.android.systemui.testKosmos
 import com.google.common.collect.Range
 import com.google.common.truth.Truth.assertThat
-import kotlin.test.Test
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
+import org.junit.Test
 import org.junit.runner.RunWith
 
 @ExperimentalCoroutinesApi
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelTest.kt
new file mode 100644
index 0000000..86b3f33
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelTest.kt
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class LockscreenToDozingTransitionViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+    private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
+    private lateinit var underTest: LockscreenToDozingTransitionViewModel
+
+    @Before
+    fun setUp() {
+        keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+        fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
+        biometricSettingsRepository = kosmos.biometricSettingsRepository
+        underTest = kosmos.lockscreenToDozingTransitionViewModel
+    }
+
+    @Test
+    fun deviceEntryParentViewAppear_udfpsEnrolledAndEnabled() =
+        testScope.runTest {
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(1f) }
+        }
+
+    @Test
+    fun deviceEntryParentViewDisappear_udfpsNotEnrolled() =
+        testScope.runTest {
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(0f) }
+        }
+
+
+    @Test
+    fun lockscreenAlphaFadesOutAndFinishesVisible() =
+        testScope.runTest {
+            val alpha by collectValues(underTest.lockscreenAlpha)
+            keyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.LOCKSCREEN,
+                to = KeyguardState.DOZING,
+                testScope,
+            )
+
+            assertThat(alpha[0]).isEqualTo(1f)
+            // Halfway through, it will have faded out
+            assertThat(alpha[1]).isEqualTo(0f)
+            // FINISHED alpha should be visible, to support pulsing
+            assertThat(alpha[2]).isEqualTo(1f)
+        }
+
+    @Test
+    fun deviceEntryBackgroundViewDisappear() =
+        testScope.runTest {
+            val values by collectValues(underTest.deviceEntryBackgroundViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(0f) }
+        }
+
+    private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep {
+        return TransitionStep(
+            from = KeyguardState.LOCKSCREEN,
+            to = KeyguardState.DOZING,
+            value = value,
+            transitionState = state,
+            ownerName = "LockscreenToDozingTransitionViewModelTest"
+        )
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt
index 7a564ac..43ab93a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt
@@ -33,10 +33,10 @@
 import com.android.systemui.testKosmos
 import com.google.common.collect.Range
 import com.google.common.truth.Truth
-import kotlin.test.Test
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
+import org.junit.Test
 import org.junit.runner.RunWith
 
 @ExperimentalCoroutinesApi
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelTest.kt
new file mode 100644
index 0000000..28473b2
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelTest.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class PrimaryBouncerToDozingTransitionViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+    private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
+    private lateinit var underTest: PrimaryBouncerToDozingTransitionViewModel
+
+    @Before
+    fun setUp() {
+        keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+        fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
+        biometricSettingsRepository = kosmos.biometricSettingsRepository
+        underTest = kosmos.primaryBouncerToDozingTransitionViewModel
+    }
+
+    @Test
+    fun deviceEntryParentViewAppear_udfpsEnrolledAndEnabled() =
+        testScope.runTest {
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(1f) }
+        }
+
+    @Test
+    fun deviceEntryParentView_udfpsNotEnrolledAndEnabled_noUpdates() =
+        testScope.runTest {
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isNull() }
+        }
+
+    @Test
+    fun deviceEntryBackgroundViewDisappear() =
+        testScope.runTest {
+            val values by collectValues(underTest.deviceEntryBackgroundViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(0f) }
+        }
+
+    private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep {
+        return TransitionStep(
+            from = KeyguardState.PRIMARY_BOUNCER,
+            to = KeyguardState.DOZING,
+            value = value,
+            transitionState = state,
+            ownerName = "PrimaryBouncerToDozingTransitionViewModelTest"
+        )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
index 47e1ee9..db1d5d9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
@@ -149,6 +149,42 @@
             values.forEach { assertThat(it).isEqualTo(1f) }
         }
 
+    @Test
+    fun notificationAlpha() =
+        testScope.runTest {
+            val values by collectValues(underTest.notificationAlpha)
+            runCurrent()
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.PRIMARY_BOUNCER,
+                to = KeyguardState.GONE,
+                testScope,
+            )
+
+            assertThat(values[0]).isEqualTo(1f)
+            // Should fade to zero between here
+            assertThat(values[1]).isEqualTo(0f)
+        }
+
+    @Test
+    fun notificationAlpha_leaveShadeOpen() =
+        testScope.runTest {
+            val values by collectValues(underTest.notificationAlpha)
+            runCurrent()
+
+            sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(true)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.PRIMARY_BOUNCER,
+                to = KeyguardState.GONE,
+                testScope,
+            )
+
+            assertThat(values.size).isEqualTo(2)
+            // Shade stays open, and alpha should remain visible
+            values.forEach { assertThat(it).isEqualTo(1f) }
+        }
+
     private fun step(
         value: Float,
         state: TransitionState = TransitionState.RUNNING
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/domain/interactor/SpatializerInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/domain/interactor/SpatializerInteractorTest.kt
new file mode 100644
index 0000000..a932dd6
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/domain/interactor/SpatializerInteractorTest.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.domain.interactor
+
+import android.media.AudioDeviceAttributes
+import android.media.AudioDeviceInfo
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.media.domain.interactor.SpatializerInteractor
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.media.spatializerRepository
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SpatializerInteractorTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+    private val underTest = SpatializerInteractor(kosmos.spatializerRepository)
+
+    @Test
+    fun setSpatialAudioEnabledFalse_isEnabled_false() {
+        with(kosmos) {
+            testScope.runTest {
+                underTest.setSpatialAudioEnabled(deviceAttributes, false)
+
+                assertThat(underTest.isSpatialAudioEnabled(deviceAttributes)).isFalse()
+            }
+        }
+    }
+
+    @Test
+    fun setSpatialAudioEnabledTrue_isEnabled_true() {
+        with(kosmos) {
+            testScope.runTest {
+                underTest.setSpatialAudioEnabled(deviceAttributes, true)
+
+                assertThat(underTest.isSpatialAudioEnabled(deviceAttributes)).isTrue()
+            }
+        }
+    }
+
+    @Test
+    fun setHeadTrackingEnabledFalse_isEnabled_false() {
+        with(kosmos) {
+            testScope.runTest {
+                underTest.setHeadTrackingEnabled(deviceAttributes, false)
+
+                assertThat(underTest.isHeadTrackingEnabled(deviceAttributes)).isFalse()
+            }
+        }
+    }
+
+    @Test
+    fun setHeadTrackingEnabledTrue_isEnabled_true() {
+        with(kosmos) {
+            testScope.runTest {
+                underTest.setHeadTrackingEnabled(deviceAttributes, true)
+
+                assertThat(underTest.isHeadTrackingEnabled(deviceAttributes)).isTrue()
+            }
+        }
+    }
+
+    private companion object {
+        val deviceAttributes =
+            AudioDeviceAttributes(
+                AudioDeviceAttributes.ROLE_OUTPUT,
+                AudioDeviceInfo.TYPE_BLE_HEADSET,
+                "test_address",
+            )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileDataInteractorTest.kt
new file mode 100644
index 0000000..266875e
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileDataInteractorTest.kt
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.rotation.domain.interactor
+
+import android.Manifest
+import android.content.packageManager
+import android.content.pm.PackageManager
+import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
+import android.testing.LeakCheck
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.camera.data.repository.fakeCameraAutoRotateRepository
+import com.android.systemui.camera.data.repository.fakeCameraSensorPrivacyRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.utils.leaks.FakeBatteryController
+import com.android.systemui.utils.leaks.FakeRotationLockController
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.toCollection
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@EnabledOnRavenwood
+@RunWith(AndroidJUnit4::class)
+class RotationLockTileDataInteractorTest : SysuiTestCase() {
+    private val kosmos = Kosmos()
+    private val testScope = kosmos.testScope
+    private val batteryController = FakeBatteryController(LeakCheck())
+    private val rotationController = FakeRotationLockController(LeakCheck())
+    private val fakeCameraAutoRotateRepository = kosmos.fakeCameraAutoRotateRepository
+    private val fakeCameraSensorPrivacyRepository = kosmos.fakeCameraSensorPrivacyRepository
+    private val packageManager = kosmos.packageManager
+
+    private val testUser = UserHandle.of(1)
+    private lateinit var underTest: RotationLockTileDataInteractor
+
+    @Before
+    fun setup() {
+        whenever(packageManager.rotationResolverPackageName).thenReturn(TEST_PACKAGE_NAME)
+        whenever(
+                packageManager.checkPermission(
+                    eq(Manifest.permission.CAMERA),
+                    eq(TEST_PACKAGE_NAME)
+                )
+            )
+            .thenReturn(PackageManager.PERMISSION_GRANTED)
+
+        underTest =
+            RotationLockTileDataInteractor(
+                rotationController,
+                batteryController,
+                fakeCameraAutoRotateRepository,
+                fakeCameraSensorPrivacyRepository,
+                packageManager,
+                context.orCreateTestableResources
+                    .apply {
+                        addOverride(com.android.internal.R.bool.config_allowRotationResolver, true)
+                    }
+                    .resources
+            )
+    }
+
+    @Test
+    fun availability_isTrue() =
+        testScope.runTest {
+            val availability = underTest.availability(testUser).toCollection(mutableListOf())
+
+            assertThat(availability).hasSize(1)
+            assertThat(availability.last()).isTrue()
+        }
+
+    @Test
+    fun tileData_isRotationLockedMatchesRotationController() =
+        testScope.runTest {
+            val data by
+                collectLastValue(
+                    underTest.tileData(testUser, flowOf(DataUpdateTrigger.InitialRequest))
+                )
+
+            runCurrent()
+            assertThat(data!!.isRotationLocked).isEqualTo(false)
+
+            rotationController.setRotationLocked(true, CALLER)
+            runCurrent()
+            assertThat(data!!.isRotationLocked).isEqualTo(true)
+
+            rotationController.setRotationLocked(false, CALLER)
+            runCurrent()
+            assertThat(data!!.isRotationLocked).isEqualTo(false)
+        }
+
+    @Test
+    fun tileData_cameraRotationMatchesBatteryController() =
+        testScope.runTest {
+            setupControllersToEnableCameraRotation()
+            val data by
+                collectLastValue(
+                    underTest.tileData(testUser, flowOf(DataUpdateTrigger.InitialRequest))
+                )
+
+            runCurrent()
+            assertThat(data!!.isCameraRotationEnabled).isTrue()
+
+            batteryController.setPowerSaveMode(true)
+            runCurrent()
+            assertThat(data!!.isCameraRotationEnabled).isFalse()
+
+            batteryController.setPowerSaveMode(false)
+            runCurrent()
+            assertThat(data!!.isCameraRotationEnabled).isTrue()
+        }
+
+    @Test
+    fun tileData_cameraRotationMatchesSensorPrivacyRepository() =
+        testScope.runTest {
+            setupControllersToEnableCameraRotation()
+            val lastValue by
+                this.collectLastValue(
+                    underTest.tileData(testUser, flowOf(DataUpdateTrigger.InitialRequest))
+                )
+            runCurrent()
+            assertThat(lastValue!!.isCameraRotationEnabled).isTrue()
+
+            fakeCameraSensorPrivacyRepository.setEnabled(testUser, true)
+            runCurrent()
+            assertThat(lastValue!!.isCameraRotationEnabled).isFalse()
+
+            fakeCameraSensorPrivacyRepository.setEnabled(testUser, false)
+            runCurrent()
+            assertThat(lastValue!!.isCameraRotationEnabled).isTrue()
+        }
+
+    @Test
+    fun tileData_cameraRotationMatchesAutoRotateRepository() =
+        testScope.runTest {
+            setupControllersToEnableCameraRotation()
+
+            val lastValue by
+                collectLastValue(
+                    underTest.tileData(testUser, flowOf(DataUpdateTrigger.InitialRequest))
+                )
+            runCurrent()
+            assertThat(lastValue!!.isCameraRotationEnabled).isTrue()
+
+            fakeCameraAutoRotateRepository.setEnabled(testUser, false)
+            runCurrent()
+            assertThat(lastValue!!.isCameraRotationEnabled).isFalse()
+
+            fakeCameraAutoRotateRepository.setEnabled(testUser, true)
+            runCurrent()
+            assertThat(lastValue!!.isCameraRotationEnabled).isTrue()
+        }
+
+    @Test
+    fun tileData_matchesPackageManagerPermissionDenied() =
+        testScope.runTest {
+            whenever(
+                    packageManager.checkPermission(
+                        eq(Manifest.permission.CAMERA),
+                        eq(TEST_PACKAGE_NAME)
+                    )
+                )
+                .thenReturn(PackageManager.PERMISSION_DENIED)
+
+            val lastValue by
+                collectLastValue(
+                    underTest.tileData(testUser, flowOf(DataUpdateTrigger.InitialRequest))
+                )
+            runCurrent()
+            assertThat(lastValue!!.isCameraRotationEnabled).isEqualTo(false)
+        }
+
+    @Test
+    fun tileData_setConfigAllowRotationResolverToFalse_cameraRotationIsNotEnabled() =
+        testScope.runTest {
+            underTest.apply {
+                overrideResource(com.android.internal.R.bool.config_allowRotationResolver, false)
+            }
+            setupControllersToEnableCameraRotation()
+            val lastValue by
+                collectLastValue(
+                    underTest.tileData(testUser, flowOf(DataUpdateTrigger.InitialRequest))
+                )
+            runCurrent()
+
+            assertThat(lastValue!!.isCameraRotationEnabled).isEqualTo(false)
+        }
+
+    private fun setupControllersToEnableCameraRotation() {
+        rotationController.setRotationLocked(true, CALLER)
+        batteryController.setPowerSaveMode(false)
+        fakeCameraSensorPrivacyRepository.setEnabled(testUser, false)
+        fakeCameraAutoRotateRepository.setEnabled(testUser, true)
+    }
+
+    private companion object {
+        private const val CALLER = "RotationLockTileDataInteractorTest"
+        private const val TEST_PACKAGE_NAME = "com.test"
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileUserActionInteractorTest.kt
new file mode 100644
index 0000000..1653ce3
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileUserActionInteractorTest.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.rotation.domain.interactor
+
+import android.platform.test.annotations.EnabledOnRavenwood
+import android.provider.Settings
+import android.testing.LeakCheck
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject
+import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
+import com.android.systemui.qs.tiles.impl.rotation.domain.model.RotationLockTileModel
+import com.android.systemui.utils.leaks.FakeRotationLockController
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@EnabledOnRavenwood
+@RunWith(AndroidJUnit4::class)
+class RotationLockTileUserActionInteractorTest : SysuiTestCase() {
+    private val controller = FakeRotationLockController(LeakCheck())
+    private val inputHandler = FakeQSTileIntentUserInputHandler()
+
+    private val underTest =
+        RotationLockTileUserActionInteractor(
+            controller,
+            inputHandler,
+        )
+
+    @Test
+    fun handleClickWhenEnabled() = runTest {
+        val wasEnabled = true
+        controller.setRotationLocked(wasEnabled, null)
+
+        underTest.handleInput(QSTileInputTestKtx.click(RotationLockTileModel(wasEnabled, false)))
+
+        assertThat(controller.isRotationLocked).isEqualTo(!wasEnabled)
+    }
+
+    @Test
+    fun handleClickWhenDisabled() = runTest {
+        val wasEnabled = false
+        controller.setRotationLocked(wasEnabled, null)
+
+        underTest.handleInput(QSTileInputTestKtx.click(RotationLockTileModel(wasEnabled, false)))
+
+        assertThat(controller.isRotationLocked).isEqualTo(!wasEnabled)
+    }
+
+    @Test
+    fun handleLongClickWhenDisabled() = runTest {
+        val enabled = false
+
+        underTest.handleInput(
+            QSTileInputTestKtx.longClick(
+                RotationLockTileModel(
+                    enabled,
+                    false,
+                )
+            )
+        )
+
+        QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+            assertThat(it.intent.action).isEqualTo(Settings.ACTION_AUTO_ROTATE_SETTINGS)
+        }
+    }
+
+    @Test
+    fun handleLongClickWhenEnabled() = runTest {
+        val enabled = true
+
+        underTest.handleInput(QSTileInputTestKtx.longClick(RotationLockTileModel(enabled, false)))
+
+        QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+            assertThat(it.intent.action).isEqualTo(Settings.ACTION_AUTO_ROTATE_SETTINGS)
+        }
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapperTest.kt
new file mode 100644
index 0000000..60c69f4
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapperTest.kt
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.rotation.ui.mapper
+
+import android.graphics.drawable.TestStubDrawable
+import android.widget.Switch
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject
+import com.android.systemui.qs.tiles.impl.rotation.domain.model.RotationLockTileModel
+import com.android.systemui.qs.tiles.impl.rotation.qsRotationLockTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.policy.DevicePostureController
+import com.android.systemui.statusbar.policy.devicePostureController
+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
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class RotationLockTileMapperTest : SysuiTestCase() {
+    private val kosmos = Kosmos()
+    private val rotationLockTileConfig = kosmos.qsRotationLockTileConfig
+    private val devicePostureController = kosmos.devicePostureController
+
+    private lateinit var mapper: RotationLockTileMapper
+
+    @Before
+    fun setup() {
+        whenever(devicePostureController.devicePosture)
+            .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED)
+
+        mapper =
+            RotationLockTileMapper(
+                context.orCreateTestableResources
+                    .apply {
+                        addOverride(R.drawable.qs_auto_rotate_icon_off, TestStubDrawable())
+                        addOverride(R.drawable.qs_auto_rotate_icon_on, TestStubDrawable())
+                        addOverride(com.android.internal.R.bool.config_allowRotationResolver, true)
+                        addOverride(
+                            com.android.internal.R.array.config_foldedDeviceStates,
+                            intArrayOf() // empty array <=> device is not foldable
+                        )
+                    }
+                    .resources,
+                context.theme,
+                devicePostureController
+            )
+    }
+
+    @Test
+    fun rotationNotLocked_cameraRotationDisabled() {
+        val inputModel = RotationLockTileModel(false, false)
+
+        val outputState = mapper.map(rotationLockTileConfig, inputModel)
+
+        val expectedState =
+            createRotationLockTileState(
+                QSTileState.ActivationState.ACTIVE,
+                EMPTY_SECONDARY_STRING,
+                R.drawable.qs_auto_rotate_icon_on
+            )
+        QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
+    }
+
+    @Test
+    fun rotationNotLocked_cameraRotationEnabled() {
+        val inputModel = RotationLockTileModel(false, true)
+
+        val outputState = mapper.map(rotationLockTileConfig, inputModel)
+
+        val expectedState =
+            createRotationLockTileState(
+                QSTileState.ActivationState.ACTIVE,
+                context.getString(R.string.rotation_lock_camera_rotation_on),
+                R.drawable.qs_auto_rotate_icon_on
+            )
+        QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
+    }
+
+    @Test
+    fun rotationLocked_cameraRotationNotEnabled() {
+        val inputModel = RotationLockTileModel(true, false)
+
+        val outputState = mapper.map(rotationLockTileConfig, inputModel)
+
+        val expectedState =
+            createRotationLockTileState(
+                QSTileState.ActivationState.INACTIVE,
+                EMPTY_SECONDARY_STRING,
+                R.drawable.qs_auto_rotate_icon_off
+            )
+        QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
+    }
+
+    @Test
+    fun deviceFoldableAndClosed_secondaryLabelIsFoldableSpecific() {
+        setDeviceFoldable()
+        val inputModel = RotationLockTileModel(false, false)
+
+        val outputState = mapper.map(rotationLockTileConfig, inputModel)
+
+        val expectedSecondaryLabelEnding =
+            context.getString(R.string.quick_settings_rotation_posture_folded)
+        assertThat(
+                context.resources.getIntArray(
+                    com.android.internal.R.array.config_foldedDeviceStates
+                )
+            )
+            .isNotEmpty()
+        val actualSecondaryLabel = outputState.secondaryLabel
+        assertThat(actualSecondaryLabel).isNotNull()
+        assertThat(actualSecondaryLabel!!.endsWith(expectedSecondaryLabelEnding)).isTrue()
+    }
+
+    @Test
+    fun deviceFoldableAndNotClosed_secondaryLabelIsFoldableSpecific() {
+        setDeviceFoldable()
+        whenever(devicePostureController.devicePosture)
+            .thenReturn(DevicePostureController.DEVICE_POSTURE_OPENED)
+        val inputModel = RotationLockTileModel(false, false)
+
+        val outputState = mapper.map(rotationLockTileConfig, inputModel)
+
+        val expectedSecondaryLabelEnding =
+            context.getString(R.string.quick_settings_rotation_posture_unfolded)
+        assertThat(
+                context.orCreateTestableResources.resources.getIntArray(
+                    com.android.internal.R.array.config_foldedDeviceStates
+                )
+            )
+            .isNotEmpty()
+        val actualSecondaryLabel = outputState.secondaryLabel
+        assertThat(actualSecondaryLabel).isNotNull()
+        assertThat(actualSecondaryLabel!!.endsWith(expectedSecondaryLabelEnding)).isTrue()
+    }
+
+    private fun setDeviceFoldable() {
+        mapper.apply {
+            overrideResource(
+                com.android.internal.R.array.config_foldedDeviceStates,
+                intArrayOf(1, 2, 3)
+            )
+        }
+    }
+
+    private fun createRotationLockTileState(
+        activationState: QSTileState.ActivationState,
+        secondaryLabel: String,
+        iconRes: Int
+    ): QSTileState {
+        val label = context.getString(R.string.quick_settings_rotation_unlocked_label)
+        return QSTileState(
+            { Icon.Loaded(context.getDrawable(iconRes)!!, null) },
+            label,
+            activationState,
+            secondaryLabel,
+            setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK),
+            context.getString(R.string.accessibility_quick_settings_rotation),
+            secondaryLabel,
+            QSTileState.SideViewIcon.None,
+            QSTileState.EnabledState.ENABLED,
+            Switch::class.qualifiedName
+        )
+    }
+
+    private companion object {
+        private const val EMPTY_SECONDARY_STRING = ""
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
index 1eb9adb..63f00c1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
@@ -18,6 +18,10 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.Back
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.SwipeDirection
+import com.android.compose.animation.scene.UserActionResult
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.flags.FakeFeatureFlagsClassic
@@ -26,10 +30,7 @@
 import com.android.systemui.qs.FooterActionsController
 import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
 import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter
-import com.android.systemui.scene.shared.model.Direction
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.shared.model.UserAction
-import com.android.systemui.scene.shared.model.UserActionResult
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.domain.interactor.privacyChipInteractor
 import com.android.systemui.shade.domain.interactor.shadeHeaderClockInteractor
 import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
@@ -121,8 +122,8 @@
             assertThat(destinations)
                 .isEqualTo(
                     mapOf(
-                        UserAction.Back to UserActionResult(SceneKey.Shade),
-                        UserAction.Swipe(Direction.UP) to UserActionResult(SceneKey.Shade),
+                        Back to UserActionResult(Scenes.Shade),
+                        Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade),
                     )
                 )
         }
@@ -136,7 +137,7 @@
             assertThat(destinations)
                 .isEqualTo(
                     mapOf(
-                        UserAction.Back to UserActionResult(SceneKey.QuickSettings),
+                        Back to UserActionResult(Scenes.QuickSettings),
                     )
                 )
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 4e72843..a2c4f4e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -22,6 +22,8 @@
 import android.telephony.TelephonyManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
 import com.android.internal.R
 import com.android.internal.util.EmergencyAffordanceManager
 import com.android.internal.util.emergencyAffordanceManager
@@ -40,6 +42,7 @@
 import com.android.systemui.bouncer.ui.viewmodel.bouncerViewModel
 import com.android.systemui.classifier.domain.interactor.falsingInteractor
 import com.android.systemui.classifier.falsingCollector
+import com.android.systemui.classifier.falsingManager
 import com.android.systemui.communal.domain.interactor.communalInteractor
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
@@ -60,8 +63,7 @@
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.domain.startable.SceneContainerStartable
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.shared.model.fakeSceneDataSource
 import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
 import com.android.systemui.settings.FakeDisplayTracker
@@ -265,6 +267,7 @@
                 displayId = displayTracker.defaultDisplayId,
                 sceneLogger = mock(),
                 falsingCollector = kosmos.falsingCollector,
+                falsingManager = kosmos.falsingManager,
                 powerInteractor = powerInteractor,
                 bouncerInteractor = bouncerInteractor,
                 simBouncerInteractor = dagger.Lazy { kosmos.simBouncerInteractor },
@@ -285,19 +288,19 @@
     }
 
     @Test
-    fun startsInLockscreenScene() = testScope.runTest { assertCurrentScene(SceneKey.Lockscreen) }
+    fun startsInLockscreenScene() = testScope.runTest { assertCurrentScene(Scenes.Lockscreen) }
 
     @Test
     fun clickLockButtonAndEnterCorrectPin_unlocksDevice() =
         testScope.runTest {
-            emulateUserDrivenTransition(SceneKey.Bouncer)
+            emulateUserDrivenTransition(Scenes.Bouncer)
 
             fakeSceneDataSource.pause()
             enterPin()
             emulatePendingTransitionProgress(
                 expectedVisible = false,
             )
-            assertCurrentScene(SceneKey.Gone)
+            assertCurrentScene(Scenes.Gone)
         }
 
     @Test
@@ -305,7 +308,7 @@
         testScope.runTest {
             val upDestinationSceneKey by
                 collectLastValue(lockscreenSceneViewModel.upDestinationSceneKey)
-            assertThat(upDestinationSceneKey).isEqualTo(SceneKey.Bouncer)
+            assertThat(upDestinationSceneKey).isEqualTo(Scenes.Bouncer)
             emulateUserDrivenTransition(
                 to = upDestinationSceneKey,
             )
@@ -315,7 +318,7 @@
             emulatePendingTransitionProgress(
                 expectedVisible = false,
             )
-            assertCurrentScene(SceneKey.Gone)
+            assertCurrentScene(Scenes.Gone)
         }
 
     @Test
@@ -325,7 +328,7 @@
 
             val upDestinationSceneKey by
                 collectLastValue(lockscreenSceneViewModel.upDestinationSceneKey)
-            assertThat(upDestinationSceneKey).isEqualTo(SceneKey.Gone)
+            assertThat(upDestinationSceneKey).isEqualTo(Scenes.Gone)
             emulateUserDrivenTransition(
                 to = upDestinationSceneKey,
             )
@@ -336,13 +339,13 @@
         testScope.runTest {
             val upDestinationSceneKey by collectLastValue(shadeSceneViewModel.upDestinationSceneKey)
             setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true)
-            assertCurrentScene(SceneKey.Lockscreen)
+            assertCurrentScene(Scenes.Lockscreen)
 
             // Emulate a user swipe to the shade scene.
-            emulateUserDrivenTransition(to = SceneKey.Shade)
-            assertCurrentScene(SceneKey.Shade)
+            emulateUserDrivenTransition(to = Scenes.Shade)
+            assertCurrentScene(Scenes.Shade)
 
-            assertThat(upDestinationSceneKey).isEqualTo(SceneKey.Lockscreen)
+            assertThat(upDestinationSceneKey).isEqualTo(Scenes.Lockscreen)
             emulateUserDrivenTransition(
                 to = upDestinationSceneKey,
             )
@@ -354,17 +357,17 @@
             val upDestinationSceneKey by collectLastValue(shadeSceneViewModel.upDestinationSceneKey)
             setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true)
             assertThat(deviceEntryInteractor.canSwipeToEnter.value).isTrue()
-            assertCurrentScene(SceneKey.Lockscreen)
+            assertCurrentScene(Scenes.Lockscreen)
 
             // Emulate a user swipe to dismiss the lockscreen.
-            emulateUserDrivenTransition(to = SceneKey.Gone)
-            assertCurrentScene(SceneKey.Gone)
+            emulateUserDrivenTransition(to = Scenes.Gone)
+            assertCurrentScene(Scenes.Gone)
 
             // Emulate a user swipe to the shade scene.
-            emulateUserDrivenTransition(to = SceneKey.Shade)
-            assertCurrentScene(SceneKey.Shade)
+            emulateUserDrivenTransition(to = Scenes.Shade)
+            assertCurrentScene(Scenes.Shade)
 
-            assertThat(upDestinationSceneKey).isEqualTo(SceneKey.Gone)
+            assertThat(upDestinationSceneKey).isEqualTo(Scenes.Gone)
             emulateUserDrivenTransition(
                 to = upDestinationSceneKey,
             )
@@ -375,10 +378,10 @@
         testScope.runTest {
             setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = false)
             putDeviceToSleep(instantlyLockDevice = false)
-            assertCurrentScene(SceneKey.Lockscreen)
+            assertCurrentScene(Scenes.Lockscreen)
 
             wakeUpDevice()
-            assertCurrentScene(SceneKey.Gone)
+            assertCurrentScene(Scenes.Gone)
         }
 
     @Test
@@ -386,45 +389,45 @@
         testScope.runTest {
             setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true)
             putDeviceToSleep(instantlyLockDevice = false)
-            assertCurrentScene(SceneKey.Lockscreen)
+            assertCurrentScene(Scenes.Lockscreen)
 
             wakeUpDevice()
-            assertCurrentScene(SceneKey.Lockscreen)
+            assertCurrentScene(Scenes.Lockscreen)
         }
 
     @Test
     fun deviceGoesToSleep_switchesToLockscreen() =
         testScope.runTest {
             unlockDevice()
-            assertCurrentScene(SceneKey.Gone)
+            assertCurrentScene(Scenes.Gone)
 
             putDeviceToSleep()
-            assertCurrentScene(SceneKey.Lockscreen)
+            assertCurrentScene(Scenes.Lockscreen)
         }
 
     @Test
     fun deviceGoesToSleep_wakeUp_unlock() =
         testScope.runTest {
             unlockDevice()
-            assertCurrentScene(SceneKey.Gone)
+            assertCurrentScene(Scenes.Gone)
             putDeviceToSleep()
-            assertCurrentScene(SceneKey.Lockscreen)
+            assertCurrentScene(Scenes.Lockscreen)
             wakeUpDevice()
-            assertCurrentScene(SceneKey.Lockscreen)
+            assertCurrentScene(Scenes.Lockscreen)
 
             unlockDevice()
-            assertCurrentScene(SceneKey.Gone)
+            assertCurrentScene(Scenes.Gone)
         }
 
     @Test
     fun deviceWakesUpWhileUnlocked_dismissesLockscreen() =
         testScope.runTest {
             unlockDevice()
-            assertCurrentScene(SceneKey.Gone)
+            assertCurrentScene(Scenes.Gone)
             putDeviceToSleep(instantlyLockDevice = false)
-            assertCurrentScene(SceneKey.Lockscreen)
+            assertCurrentScene(Scenes.Lockscreen)
             wakeUpDevice()
-            assertCurrentScene(SceneKey.Gone)
+            assertCurrentScene(Scenes.Gone)
         }
 
     @Test
@@ -433,20 +436,20 @@
             unlockDevice()
             val upDestinationSceneKey by
                 collectLastValue(lockscreenSceneViewModel.upDestinationSceneKey)
-            assertThat(upDestinationSceneKey).isEqualTo(SceneKey.Gone)
+            assertThat(upDestinationSceneKey).isEqualTo(Scenes.Gone)
         }
 
     @Test
     fun deviceGoesToSleep_withLockTimeout_staysOnLockscreen() =
         testScope.runTest {
             unlockDevice()
-            assertCurrentScene(SceneKey.Gone)
+            assertCurrentScene(Scenes.Gone)
             putDeviceToSleep(instantlyLockDevice = false)
-            assertCurrentScene(SceneKey.Lockscreen)
+            assertCurrentScene(Scenes.Lockscreen)
 
             // Pretend like the timeout elapsed and now lock the device.
             lockDevice()
-            assertCurrentScene(SceneKey.Lockscreen)
+            assertCurrentScene(Scenes.Lockscreen)
         }
 
     @Test
@@ -455,7 +458,7 @@
             setAuthMethod(AuthenticationMethodModel.Password)
             val upDestinationSceneKey by
                 collectLastValue(lockscreenSceneViewModel.upDestinationSceneKey)
-            assertThat(upDestinationSceneKey).isEqualTo(SceneKey.Bouncer)
+            assertThat(upDestinationSceneKey).isEqualTo(Scenes.Bouncer)
             emulateUserDrivenTransition(
                 to = upDestinationSceneKey,
             )
@@ -464,7 +467,7 @@
             dismissIme()
 
             emulatePendingTransitionProgress()
-            assertCurrentScene(SceneKey.Lockscreen)
+            assertCurrentScene(Scenes.Lockscreen)
         }
 
     @Test
@@ -473,7 +476,7 @@
             setAuthMethod(AuthenticationMethodModel.Password)
             val upDestinationSceneKey by
                 collectLastValue(lockscreenSceneViewModel.upDestinationSceneKey)
-            assertThat(upDestinationSceneKey).isEqualTo(SceneKey.Bouncer)
+            assertThat(upDestinationSceneKey).isEqualTo(Scenes.Bouncer)
             emulateUserDrivenTransition(to = upDestinationSceneKey)
 
             val bouncerActionButton by collectLastValue(bouncerViewModel.actionButton)
@@ -493,7 +496,7 @@
             startPhoneCall()
             val upDestinationSceneKey by
                 collectLastValue(lockscreenSceneViewModel.upDestinationSceneKey)
-            assertThat(upDestinationSceneKey).isEqualTo(SceneKey.Bouncer)
+            assertThat(upDestinationSceneKey).isEqualTo(Scenes.Bouncer)
             emulateUserDrivenTransition(to = upDestinationSceneKey)
 
             val bouncerActionButton by collectLastValue(bouncerViewModel.actionButton)
@@ -511,7 +514,7 @@
         testScope.runTest {
             setAuthMethod(AuthenticationMethodModel.None)
             introduceLockedSim()
-            assertCurrentScene(SceneKey.Bouncer)
+            assertCurrentScene(Scenes.Bouncer)
         }
 
     @Test
@@ -521,7 +524,7 @@
             introduceLockedSim()
             emulatePendingTransitionProgress(expectedVisible = true)
             enterSimPin(authMethodAfterSimUnlock = AuthenticationMethodModel.None)
-            assertCurrentScene(SceneKey.Gone)
+            assertCurrentScene(Scenes.Gone)
         }
 
     @Test
@@ -531,7 +534,7 @@
             introduceLockedSim()
             emulatePendingTransitionProgress(expectedVisible = true)
             enterSimPin(authMethodAfterSimUnlock = AuthenticationMethodModel.Pin)
-            assertCurrentScene(SceneKey.Lockscreen)
+            assertCurrentScene(Scenes.Lockscreen)
         }
 
     @Test
@@ -613,6 +616,7 @@
     private fun TestScope.emulatePendingTransitionProgress(
         expectedVisible: Boolean = true,
     ) {
+        val isVisible by collectLastValue(sceneContainerViewModel.isVisible)
         assertWithMessage("The FakeSceneDataSource has to be paused for this to do anything.")
             .that(fakeSceneDataSource.isPaused)
             .isTrue()
@@ -649,12 +653,12 @@
         runCurrent()
 
         assertWithMessage("Visibility mismatch after scene transition from $from to $to!")
-            .that(sceneContainerViewModel.isVisible.value)
+            .that(isVisible)
             .isEqualTo(expectedVisible)
         assertThat(sceneContainerViewModel.currentScene.value).isEqualTo(to)
 
         bouncerSceneJob =
-            if (to == SceneKey.Bouncer) {
+            if (to == Scenes.Bouncer) {
                 testScope.backgroundScope.launch {
                     bouncerViewModel.authMethodViewModel.collect {
                         // Do nothing. Need this to turn this otherwise cold flow, hot.
@@ -685,7 +689,7 @@
         sceneInteractor.changeScene(to, "reason")
 
         emulatePendingTransitionProgress(
-            expectedVisible = to != SceneKey.Gone,
+            expectedVisible = to != Scenes.Gone,
         )
     }
 
@@ -712,7 +716,7 @@
             .that(deviceEntryInteractor.isUnlocked.value)
             .isFalse()
 
-        emulateUserDrivenTransition(SceneKey.Bouncer)
+        emulateUserDrivenTransition(Scenes.Bouncer)
         fakeSceneDataSource.pause()
         enterPin()
         // This repository state is not changed by the AuthInteractor, it relies on
@@ -726,7 +730,7 @@
     /**
      * Enters the correct PIN in the bouncer UI.
      *
-     * Asserts that the current scene is [SceneKey.Bouncer] and that the current bouncer UI is a PIN
+     * Asserts that the current scene is [Scenes.Bouncer] and that the current bouncer UI is a PIN
      * before proceeding.
      *
      * Does not assert that the device is locked or unlocked.
@@ -734,7 +738,7 @@
     private fun TestScope.enterPin() {
         assertWithMessage("Cannot enter PIN when not on the Bouncer scene!")
             .that(getCurrentSceneInUi())
-            .isEqualTo(SceneKey.Bouncer)
+            .isEqualTo(Scenes.Bouncer)
         val authMethodViewModel by collectLastValue(bouncerViewModel.authMethodViewModel)
         assertWithMessage("Cannot enter PIN when not using a PIN authentication method!")
             .that(authMethodViewModel)
@@ -751,7 +755,7 @@
     /**
      * Enters the correct PIN in the sim bouncer UI.
      *
-     * Asserts that the current scene is [SceneKey.Bouncer] and that the current bouncer UI is a PIN
+     * Asserts that the current scene is [Scenes.Bouncer] and that the current bouncer UI is a PIN
      * before proceeding.
      *
      * Does not assert that the device is locked or unlocked.
@@ -761,7 +765,7 @@
     ) {
         assertWithMessage("Cannot enter PIN when not on the Bouncer scene!")
             .that(getCurrentSceneInUi())
-            .isEqualTo(SceneKey.Bouncer)
+            .isEqualTo(Scenes.Bouncer)
         val authMethodViewModel by collectLastValue(bouncerViewModel.authMethodViewModel)
         assertWithMessage("Cannot enter PIN when not using a PIN authentication method!")
             .that(authMethodViewModel)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
index 1da3bc1..3d66192 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
@@ -20,14 +20,14 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.scene.sceneContainerConfig
 import com.android.systemui.scene.sceneKeys
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -51,12 +51,12 @@
         assertThat(underTest.allSceneKeys())
             .isEqualTo(
                 listOf(
-                    SceneKey.QuickSettings,
-                    SceneKey.Shade,
-                    SceneKey.Lockscreen,
-                    SceneKey.Bouncer,
-                    SceneKey.Gone,
-                    SceneKey.Communal,
+                    Scenes.QuickSettings,
+                    Scenes.Shade,
+                    Scenes.Lockscreen,
+                    Scenes.Bouncer,
+                    Scenes.Gone,
+                    Scenes.Communal,
                 )
             )
     }
@@ -66,17 +66,17 @@
         testScope.runTest {
             val underTest = kosmos.sceneContainerRepository
             val currentScene by collectLastValue(underTest.currentScene)
-            assertThat(currentScene).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
 
-            underTest.changeScene(SceneKey.Shade)
-            assertThat(currentScene).isEqualTo(SceneKey.Shade)
+            underTest.changeScene(Scenes.Shade)
+            assertThat(currentScene).isEqualTo(Scenes.Shade)
         }
 
     @Test(expected = IllegalStateException::class)
     fun changeScene_noSuchSceneInContainer_throws() {
-        kosmos.sceneKeys = listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)
+        kosmos.sceneKeys = listOf(Scenes.QuickSettings, Scenes.Lockscreen)
         val underTest = kosmos.sceneContainerRepository
-        underTest.changeScene(SceneKey.Shade)
+        underTest.changeScene(Scenes.Shade)
     }
 
     @Test
@@ -111,7 +111,7 @@
             val underTest = kosmos.sceneContainerRepository
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
-                    ObservableTransitionState.Idle(SceneKey.Lockscreen)
+                    ObservableTransitionState.Idle(Scenes.Lockscreen)
                 )
             underTest.setTransitionState(transitionState)
             val reflectedTransitionState by collectLastValue(underTest.transitionState)
@@ -120,8 +120,8 @@
             val progress = MutableStateFlow(1f)
             transitionState.value =
                 ObservableTransitionState.Transition(
-                    fromScene = SceneKey.Lockscreen,
-                    toScene = SceneKey.Shade,
+                    fromScene = Scenes.Lockscreen,
+                    toScene = Scenes.Shade,
                     progress = progress,
                     isInitiatedByUserInput = false,
                     isUserInputOngoing = flowOf(false),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractorTest.kt
new file mode 100644
index 0000000..6b5997f
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractorTest.kt
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.scene.domain.interactor
+
+import android.platform.test.annotations.DisableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
+import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
+import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.shared.model.fakeSceneDataSource
+import com.android.systemui.shade.data.repository.fakeShadeRepository
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.panelExpansionInteractor
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class PanelExpansionInteractorTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private val deviceEntryRepository = kosmos.fakeDeviceEntryRepository
+    private val deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor
+    private val sceneInteractor = kosmos.sceneInteractor
+    private val transitionState =
+        MutableStateFlow<ObservableTransitionState>(
+            ObservableTransitionState.Idle(Scenes.Lockscreen)
+        )
+    private val fakeSceneDataSource = kosmos.fakeSceneDataSource
+    private val fakeShadeRepository = kosmos.fakeShadeRepository
+
+    private lateinit var underTest: PanelExpansionInteractor
+
+    @Before
+    fun setUp() {
+        sceneInteractor.setTransitionState(transitionState)
+    }
+
+    @Test
+    @EnableSceneContainer
+    fun legacyPanelExpansion_whenIdle_whenLocked() =
+        testScope.runTest {
+            underTest = kosmos.panelExpansionInteractor
+            setUnlocked(false)
+            val panelExpansion by collectLastValue(underTest.legacyPanelExpansion)
+
+            changeScene(Scenes.Lockscreen) { assertThat(panelExpansion).isEqualTo(1f) }
+            assertThat(panelExpansion).isEqualTo(1f)
+
+            changeScene(Scenes.Bouncer) { assertThat(panelExpansion).isEqualTo(1f) }
+            assertThat(panelExpansion).isEqualTo(1f)
+
+            changeScene(Scenes.Shade) { assertThat(panelExpansion).isEqualTo(1f) }
+            assertThat(panelExpansion).isEqualTo(1f)
+
+            changeScene(Scenes.QuickSettings) { assertThat(panelExpansion).isEqualTo(1f) }
+            assertThat(panelExpansion).isEqualTo(1f)
+
+            changeScene(Scenes.Communal) { assertThat(panelExpansion).isEqualTo(1f) }
+            assertThat(panelExpansion).isEqualTo(1f)
+        }
+
+    @Test
+    @EnableSceneContainer
+    fun legacyPanelExpansion_whenIdle_whenUnlocked() =
+        testScope.runTest {
+            underTest = kosmos.panelExpansionInteractor
+            setUnlocked(true)
+            val panelExpansion by collectLastValue(underTest.legacyPanelExpansion)
+
+            changeScene(Scenes.Gone) { assertThat(panelExpansion).isEqualTo(0f) }
+            assertThat(panelExpansion).isEqualTo(0f)
+
+            changeScene(Scenes.Shade) { progress -> assertThat(panelExpansion).isEqualTo(progress) }
+            assertThat(panelExpansion).isEqualTo(1f)
+
+            changeScene(Scenes.QuickSettings) {
+                // Shade's already expanded, so moving to QS should also be 1f.
+                assertThat(panelExpansion).isEqualTo(1f)
+            }
+            assertThat(panelExpansion).isEqualTo(1f)
+
+            changeScene(Scenes.Communal) { assertThat(panelExpansion).isEqualTo(1f) }
+            assertThat(panelExpansion).isEqualTo(1f)
+        }
+
+    @Test
+    @DisableFlags(FLAG_SCENE_CONTAINER)
+    fun legacyPanelExpansion_whenInLegacyMode() =
+        testScope.runTest {
+            underTest = kosmos.panelExpansionInteractor
+            val leet = 0.1337f
+            fakeShadeRepository.setLegacyShadeExpansion(leet)
+            setUnlocked(false)
+            val panelExpansion by collectLastValue(underTest.legacyPanelExpansion)
+
+            changeScene(Scenes.Lockscreen)
+            assertThat(panelExpansion).isEqualTo(leet)
+
+            changeScene(Scenes.Bouncer)
+            assertThat(panelExpansion).isEqualTo(leet)
+
+            changeScene(Scenes.Shade)
+            assertThat(panelExpansion).isEqualTo(leet)
+
+            changeScene(Scenes.QuickSettings)
+            assertThat(panelExpansion).isEqualTo(leet)
+
+            changeScene(Scenes.Communal)
+            assertThat(panelExpansion).isEqualTo(leet)
+        }
+
+    private fun TestScope.setUnlocked(isUnlocked: Boolean) {
+        val isDeviceUnlocked by collectLastValue(deviceUnlockedInteractor.isDeviceUnlocked)
+        deviceEntryRepository.setUnlocked(isUnlocked)
+        runCurrent()
+
+        assertThat(isDeviceUnlocked).isEqualTo(isUnlocked)
+    }
+
+    private fun TestScope.changeScene(
+        toScene: SceneKey,
+        assertDuringProgress: ((progress: Float) -> Unit) = {},
+    ) {
+        val currentScene by collectLastValue(sceneInteractor.currentScene)
+        val progressFlow = MutableStateFlow(0f)
+        transitionState.value =
+            ObservableTransitionState.Transition(
+                fromScene = checkNotNull(currentScene),
+                toScene = toScene,
+                progress = progressFlow,
+                isInitiatedByUserInput = true,
+                isUserInputOngoing = flowOf(true),
+            )
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        progressFlow.value = 0.2f
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        progressFlow.value = 0.6f
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        progressFlow.value = 1f
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        transitionState.value = ObservableTransitionState.Idle(toScene)
+        fakeSceneDataSource.changeScene(toScene)
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        assertThat(currentScene).isEqualTo(toScene)
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index dd3eb68..f645f1c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
 package com.android.systemui.scene.domain.interactor
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
@@ -26,11 +29,11 @@
 import com.android.systemui.scene.sceneContainerConfig
 import com.android.systemui.scene.sceneKeys
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.shared.model.fakeSceneDataSource
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.test.runCurrent
@@ -64,23 +67,23 @@
     fun changeScene() =
         testScope.runTest {
             val currentScene by collectLastValue(underTest.currentScene)
-            assertThat(currentScene).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
 
-            underTest.changeScene(SceneKey.Shade, "reason")
-            assertThat(currentScene).isEqualTo(SceneKey.Shade)
+            underTest.changeScene(Scenes.Shade, "reason")
+            assertThat(currentScene).isEqualTo(Scenes.Shade)
         }
 
     @Test
     fun changeScene_toGoneWhenUnl_doesNotThrow() =
         testScope.runTest {
             val currentScene by collectLastValue(underTest.currentScene)
-            assertThat(currentScene).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
 
             kosmos.fakeDeviceEntryRepository.setUnlocked(true)
             runCurrent()
 
-            underTest.changeScene(SceneKey.Gone, "reason")
-            assertThat(currentScene).isEqualTo(SceneKey.Gone)
+            underTest.changeScene(Scenes.Gone, "reason")
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
         }
 
     @Test(expected = IllegalStateException::class)
@@ -88,18 +91,18 @@
         testScope.runTest {
             kosmos.fakeDeviceEntryRepository.setUnlocked(false)
 
-            underTest.changeScene(SceneKey.Gone, "reason")
+            underTest.changeScene(Scenes.Gone, "reason")
         }
 
     @Test
     fun sceneChanged_inDataSource() =
         testScope.runTest {
             val currentScene by collectLastValue(underTest.currentScene)
-            assertThat(currentScene).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
 
-            fakeSceneDataSource.changeScene(SceneKey.Shade)
+            fakeSceneDataSource.changeScene(Scenes.Shade)
 
-            assertThat(currentScene).isEqualTo(SceneKey.Shade)
+            assertThat(currentScene).isEqualTo(Scenes.Shade)
         }
 
     @Test
@@ -108,7 +111,7 @@
             val underTest = kosmos.sceneContainerRepository
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
-                    ObservableTransitionState.Idle(SceneKey.Lockscreen)
+                    ObservableTransitionState.Idle(Scenes.Lockscreen)
                 )
             underTest.setTransitionState(transitionState)
             val reflectedTransitionState by collectLastValue(underTest.transitionState)
@@ -117,8 +120,8 @@
             val progress = MutableStateFlow(1f)
             transitionState.value =
                 ObservableTransitionState.Transition(
-                    fromScene = SceneKey.Lockscreen,
-                    toScene = SceneKey.Shade,
+                    fromScene = Scenes.Lockscreen,
+                    toScene = Scenes.Shade,
                     progress = progress,
                     isInitiatedByUserInput = false,
                     isUserInputOngoing = flowOf(false),
@@ -150,27 +153,27 @@
             val transitionTo by collectLastValue(underTest.transitioningTo)
             assertThat(transitionTo).isNull()
 
-            underTest.changeScene(SceneKey.Shade, "reason")
+            underTest.changeScene(Scenes.Shade, "reason")
             assertThat(transitionTo).isNull()
 
             val progress = MutableStateFlow(0f)
             transitionState.value =
                 ObservableTransitionState.Transition(
                     fromScene = underTest.currentScene.value,
-                    toScene = SceneKey.Shade,
+                    toScene = Scenes.Shade,
                     progress = progress,
                     isInitiatedByUserInput = false,
                     isUserInputOngoing = flowOf(false),
                 )
-            assertThat(transitionTo).isEqualTo(SceneKey.Shade)
+            assertThat(transitionTo).isEqualTo(Scenes.Shade)
 
             progress.value = 0.5f
-            assertThat(transitionTo).isEqualTo(SceneKey.Shade)
+            assertThat(transitionTo).isEqualTo(Scenes.Shade)
 
             progress.value = 1f
-            assertThat(transitionTo).isEqualTo(SceneKey.Shade)
+            assertThat(transitionTo).isEqualTo(Scenes.Shade)
 
-            transitionState.value = ObservableTransitionState.Idle(SceneKey.Shade)
+            transitionState.value = ObservableTransitionState.Idle(Scenes.Shade)
             assertThat(transitionTo).isNull()
         }
 
@@ -179,7 +182,7 @@
         testScope.runTest {
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
-                    ObservableTransitionState.Idle(SceneKey.Shade)
+                    ObservableTransitionState.Idle(Scenes.Shade)
                 )
             val isTransitionUserInputOngoing by
                 collectLastValue(underTest.isTransitionUserInputOngoing)
@@ -194,8 +197,8 @@
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
-                        fromScene = SceneKey.Shade,
-                        toScene = SceneKey.Lockscreen,
+                        fromScene = Scenes.Shade,
+                        toScene = Scenes.Lockscreen,
                         progress = flowOf(0.5f),
                         isInitiatedByUserInput = true,
                         isUserInputOngoing = flowOf(true),
@@ -214,8 +217,8 @@
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
-                        fromScene = SceneKey.Shade,
-                        toScene = SceneKey.Lockscreen,
+                        fromScene = Scenes.Shade,
+                        toScene = Scenes.Lockscreen,
                         progress = flowOf(0.5f),
                         isInitiatedByUserInput = true,
                         isUserInputOngoing = flowOf(true),
@@ -229,8 +232,8 @@
 
             transitionState.value =
                 ObservableTransitionState.Transition(
-                    fromScene = SceneKey.Shade,
-                    toScene = SceneKey.Lockscreen,
+                    fromScene = Scenes.Shade,
+                    toScene = Scenes.Lockscreen,
                     progress = flowOf(0.6f),
                     isInitiatedByUserInput = true,
                     isUserInputOngoing = flowOf(false),
@@ -245,8 +248,8 @@
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
-                        fromScene = SceneKey.Shade,
-                        toScene = SceneKey.Lockscreen,
+                        fromScene = Scenes.Shade,
+                        toScene = Scenes.Lockscreen,
                         progress = flowOf(0.5f),
                         isInitiatedByUserInput = true,
                         isUserInputOngoing = flowOf(true),
@@ -258,7 +261,7 @@
 
             assertThat(isTransitionUserInputOngoing).isTrue()
 
-            transitionState.value = ObservableTransitionState.Idle(scene = SceneKey.Lockscreen)
+            transitionState.value = ObservableTransitionState.Idle(scene = Scenes.Lockscreen)
 
             assertThat(isTransitionUserInputOngoing).isFalse()
         }
@@ -275,4 +278,18 @@
             underTest.setVisible(true, "reason")
             assertThat(isVisible).isTrue()
         }
+
+    @Test
+    fun isVisible_duringRemoteUserInteraction_forcedVisible() =
+        testScope.runTest {
+            underTest.setVisible(false, "reason")
+            val isVisible by collectLastValue(underTest.isVisible)
+            assertThat(isVisible).isFalse()
+            underTest.onRemoteUserInteractionStarted("reason")
+            assertThat(isVisible).isTrue()
+
+            underTest.onUserInteractionFinished()
+
+            assertThat(isVisible).isFalse()
+        }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index f49b477..cc66f8b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -24,6 +24,8 @@
 import android.view.Display
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.Flags as AconfigFlags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
@@ -32,6 +34,7 @@
 import com.android.systemui.bouncer.domain.interactor.bouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.simBouncerInteractor
 import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.classifier.falsingManager
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
 import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
@@ -45,8 +48,7 @@
 import com.android.systemui.power.domain.interactor.PowerInteractorFactory
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.shared.model.fakeSceneDataSource
 import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
@@ -115,6 +117,7 @@
                 displayId = Display.DEFAULT_DISPLAY,
                 sceneLogger = mock(),
                 falsingCollector = falsingCollector,
+                falsingManager = kosmos.falsingManager,
                 powerInteractor = powerInteractor,
                 bouncerInteractor = bouncerInteractor,
                 simBouncerInteractor = { kosmos.simBouncerInteractor },
@@ -134,42 +137,42 @@
             val transitionStateFlow =
                 prepareState(
                     isDeviceUnlocked = true,
-                    initialSceneKey = SceneKey.Gone,
+                    initialSceneKey = Scenes.Gone,
                 )
-            assertThat(currentDesiredSceneKey).isEqualTo(SceneKey.Gone)
+            assertThat(currentDesiredSceneKey).isEqualTo(Scenes.Gone)
             assertThat(isVisible).isTrue()
 
             underTest.start()
             assertThat(isVisible).isFalse()
 
             fakeSceneDataSource.pause()
-            sceneInteractor.changeScene(SceneKey.Shade, "reason")
+            sceneInteractor.changeScene(Scenes.Shade, "reason")
             transitionStateFlow.value =
                 ObservableTransitionState.Transition(
-                    fromScene = SceneKey.Gone,
-                    toScene = SceneKey.Shade,
+                    fromScene = Scenes.Gone,
+                    toScene = Scenes.Shade,
                     progress = flowOf(0.5f),
                     isInitiatedByUserInput = false,
                     isUserInputOngoing = flowOf(false),
                 )
             assertThat(isVisible).isTrue()
-            fakeSceneDataSource.unpause(expectedScene = SceneKey.Shade)
-            transitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Shade)
+            fakeSceneDataSource.unpause(expectedScene = Scenes.Shade)
+            transitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Shade)
             assertThat(isVisible).isTrue()
 
             fakeSceneDataSource.pause()
-            sceneInteractor.changeScene(SceneKey.Gone, "reason")
+            sceneInteractor.changeScene(Scenes.Gone, "reason")
             transitionStateFlow.value =
                 ObservableTransitionState.Transition(
-                    fromScene = SceneKey.Shade,
-                    toScene = SceneKey.Gone,
+                    fromScene = Scenes.Shade,
+                    toScene = Scenes.Gone,
                     progress = flowOf(0.5f),
                     isInitiatedByUserInput = false,
                     isUserInputOngoing = flowOf(false),
                 )
             assertThat(isVisible).isTrue()
-            fakeSceneDataSource.unpause(expectedScene = SceneKey.Gone)
-            transitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Gone)
+            fakeSceneDataSource.unpause(expectedScene = Scenes.Gone)
+            transitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Gone)
             assertThat(isVisible).isFalse()
 
             kosmos.headsUpNotificationRepository.hasPinnedHeadsUp.value = true
@@ -185,7 +188,7 @@
             val isVisible by collectLastValue(sceneInteractor.isVisible)
             prepareState(
                 isDeviceUnlocked = true,
-                initialSceneKey = SceneKey.Lockscreen,
+                initialSceneKey = Scenes.Lockscreen,
                 isDeviceProvisioned = false,
                 isFrpActive = true,
             )
@@ -212,7 +215,7 @@
             underTest.start()
             runCurrent()
 
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
         }
 
     @Test
@@ -221,14 +224,14 @@
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             prepareState(
                 isDeviceUnlocked = true,
-                initialSceneKey = SceneKey.Gone,
+                initialSceneKey = Scenes.Gone,
             )
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Gone)
             underTest.start()
 
             kosmos.fakeDeviceEntryRepository.setUnlocked(false)
 
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
         }
 
     @Test
@@ -237,14 +240,14 @@
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             prepareState(
                 isDeviceUnlocked = false,
-                initialSceneKey = SceneKey.Bouncer,
+                initialSceneKey = Scenes.Bouncer,
             )
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Bouncer)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Bouncer)
             underTest.start()
 
             kosmos.fakeDeviceEntryRepository.setUnlocked(true)
 
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Gone)
         }
 
     @Test
@@ -253,14 +256,14 @@
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             prepareState(
                 isBypassEnabled = true,
-                initialSceneKey = SceneKey.Lockscreen,
+                initialSceneKey = Scenes.Lockscreen,
             )
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
             underTest.start()
 
             kosmos.fakeDeviceEntryRepository.setUnlocked(true)
 
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Gone)
         }
 
     @Test
@@ -269,16 +272,16 @@
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             prepareState(
                 isBypassEnabled = false,
-                initialSceneKey = SceneKey.Lockscreen,
+                initialSceneKey = Scenes.Lockscreen,
             )
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
             underTest.start()
 
             // Authenticate using a passive auth method like face auth while bypass is disabled.
             faceAuthRepository.isAuthenticated.value = true
             kosmos.fakeDeviceEntryRepository.setUnlocked(true)
 
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
         }
 
     @Test
@@ -289,19 +292,19 @@
                 prepareState(
                     isBypassEnabled = true,
                     authenticationMethod = AuthenticationMethodModel.Pin,
-                    initialSceneKey = SceneKey.Lockscreen,
+                    initialSceneKey = Scenes.Lockscreen,
                 )
             underTest.start()
             runCurrent()
 
-            sceneInteractor.changeScene(SceneKey.Shade, "switch to shade")
-            transitionStateFlowValue.value = ObservableTransitionState.Idle(SceneKey.Shade)
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
+            sceneInteractor.changeScene(Scenes.Shade, "switch to shade")
+            transitionStateFlowValue.value = ObservableTransitionState.Idle(Scenes.Shade)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Shade)
 
             kosmos.fakeDeviceEntryRepository.setUnlocked(true)
             runCurrent()
 
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Shade)
         }
 
     @Test
@@ -310,16 +313,16 @@
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             prepareState(
                 isBypassEnabled = false,
-                initialSceneKey = SceneKey.Bouncer,
+                initialSceneKey = Scenes.Bouncer,
             )
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Bouncer)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Bouncer)
             underTest.start()
 
             // Authenticate using a passive auth method like face auth while bypass is disabled.
             faceAuthRepository.isAuthenticated.value = true
             kosmos.fakeDeviceEntryRepository.setUnlocked(true)
 
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Gone)
         }
 
     @Test
@@ -328,13 +331,13 @@
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             prepareState(
                 isDeviceUnlocked = false,
-                initialSceneKey = SceneKey.Shade,
+                initialSceneKey = Scenes.Shade,
             )
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Shade)
             underTest.start()
             powerInteractor.setAsleepForTest()
 
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
         }
 
     @Test
@@ -346,14 +349,14 @@
             clearInvocations(sysUiState)
 
             listOf(
-                    SceneKey.Gone,
-                    SceneKey.Lockscreen,
-                    SceneKey.Bouncer,
-                    SceneKey.Shade,
-                    SceneKey.QuickSettings,
+                    Scenes.Gone,
+                    Scenes.Lockscreen,
+                    Scenes.Bouncer,
+                    Scenes.Shade,
+                    Scenes.QuickSettings,
                 )
                 .forEachIndexed { index, sceneKey ->
-                    if (sceneKey == SceneKey.Gone) {
+                    if (sceneKey == Scenes.Gone) {
                         kosmos.fakeDeviceEntryRepository.setUnlocked(true)
                         runCurrent()
                     }
@@ -377,15 +380,15 @@
         testScope.runTest {
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             prepareState(
-                initialSceneKey = SceneKey.Lockscreen,
+                initialSceneKey = Scenes.Lockscreen,
                 authenticationMethod = AuthenticationMethodModel.None,
                 isLockscreenEnabled = false,
             )
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
             underTest.start()
             powerInteractor.setAwakeForTest()
 
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Gone)
         }
 
     @Test
@@ -393,15 +396,15 @@
         testScope.runTest {
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             prepareState(
-                initialSceneKey = SceneKey.Lockscreen,
+                initialSceneKey = Scenes.Lockscreen,
                 authenticationMethod = AuthenticationMethodModel.None,
                 isLockscreenEnabled = true,
             )
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
             underTest.start()
             powerInteractor.setAwakeForTest()
 
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
         }
 
     @Test
@@ -409,14 +412,14 @@
         testScope.runTest {
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             prepareState(
-                initialSceneKey = SceneKey.Lockscreen,
+                initialSceneKey = Scenes.Lockscreen,
                 authenticationMethod = AuthenticationMethodModel.Pin,
             )
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
             underTest.start()
             powerInteractor.setAwakeForTest()
 
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
         }
 
     @Test
@@ -424,12 +427,12 @@
         testScope.runTest {
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             prepareState(
-                initialSceneKey = SceneKey.Lockscreen,
+                initialSceneKey = Scenes.Lockscreen,
                 authenticationMethod = AuthenticationMethodModel.Pin,
                 isDeviceUnlocked = false,
                 startsAwake = false
             )
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
             underTest.start()
 
             kosmos.fakeDeviceEntryRepository.setUnlocked(true)
@@ -437,14 +440,14 @@
             powerInteractor.setAwakeForTest()
             runCurrent()
 
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Gone)
         }
 
     @Test
     fun collectFalsingSignals_onSuccessfulUnlock() =
         testScope.runTest {
             prepareState(
-                initialSceneKey = SceneKey.Lockscreen,
+                initialSceneKey = Scenes.Lockscreen,
                 authenticationMethod = AuthenticationMethodModel.Pin,
                 isDeviceUnlocked = false,
             )
@@ -454,11 +457,11 @@
 
             // Move around scenes without unlocking.
             listOf(
-                    SceneKey.Shade,
-                    SceneKey.QuickSettings,
-                    SceneKey.Shade,
-                    SceneKey.Lockscreen,
-                    SceneKey.Bouncer,
+                    Scenes.Shade,
+                    Scenes.QuickSettings,
+                    Scenes.Shade,
+                    Scenes.Lockscreen,
+                    Scenes.Bouncer,
                 )
                 .forEach { sceneKey ->
                     sceneInteractor.changeScene(sceneKey, "reason")
@@ -469,17 +472,17 @@
             // Changing to the Gone scene should report a successful unlock.
             kosmos.fakeDeviceEntryRepository.setUnlocked(true)
             runCurrent()
-            sceneInteractor.changeScene(SceneKey.Gone, "reason")
+            sceneInteractor.changeScene(Scenes.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,
+                    Scenes.Shade,
+                    Scenes.QuickSettings,
+                    Scenes.Shade,
+                    Scenes.Gone,
                 )
                 .forEach { sceneKey ->
                     sceneInteractor.changeScene(sceneKey, "reason")
@@ -488,17 +491,17 @@
                 }
 
             // Changing to the Lockscreen scene shouldn't report a successful unlock.
-            sceneInteractor.changeScene(SceneKey.Lockscreen, "reason")
+            sceneInteractor.changeScene(Scenes.Lockscreen, "reason")
             runCurrent()
             verify(falsingCollector, times(1)).onSuccessfulUnlock()
 
             // Move around scenes without unlocking.
             listOf(
-                    SceneKey.Shade,
-                    SceneKey.QuickSettings,
-                    SceneKey.Shade,
-                    SceneKey.Lockscreen,
-                    SceneKey.Bouncer,
+                    Scenes.Shade,
+                    Scenes.QuickSettings,
+                    Scenes.Shade,
+                    Scenes.Lockscreen,
+                    Scenes.Bouncer,
                 )
                 .forEach { sceneKey ->
                     sceneInteractor.changeScene(sceneKey, "reason")
@@ -507,7 +510,7 @@
                 }
 
             // Changing to the Gone scene should report a second successful unlock.
-            sceneInteractor.changeScene(SceneKey.Gone, "reason")
+            sceneInteractor.changeScene(Scenes.Gone, "reason")
             runCurrent()
             verify(falsingCollector, times(2)).onSuccessfulUnlock()
         }
@@ -516,7 +519,7 @@
     fun collectFalsingSignals_setShowingAod() =
         testScope.runTest {
             prepareState(
-                initialSceneKey = SceneKey.Lockscreen,
+                initialSceneKey = Scenes.Lockscreen,
                 authenticationMethod = AuthenticationMethodModel.Pin,
                 isDeviceUnlocked = false,
             )
@@ -538,7 +541,7 @@
         testScope.runTest {
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
             prepareState(
-                initialSceneKey = SceneKey.Lockscreen,
+                initialSceneKey = Scenes.Lockscreen,
                 authenticationMethod = AuthenticationMethodModel.Password,
                 isDeviceUnlocked = false,
             )
@@ -548,7 +551,7 @@
             bouncerInteractor.onImeHiddenByUser()
             runCurrent()
 
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
         }
 
     @Test
@@ -557,7 +560,7 @@
             kosmos.fakeKeyguardRepository.setAodAvailable(false)
             runCurrent()
             prepareState(
-                initialSceneKey = SceneKey.Lockscreen,
+                initialSceneKey = Scenes.Lockscreen,
                 authenticationMethod = AuthenticationMethodModel.Pin,
                 isDeviceUnlocked = false,
                 startsAwake = false,
@@ -605,7 +608,7 @@
             kosmos.fakeKeyguardRepository.setAodAvailable(true)
             runCurrent()
             prepareState(
-                initialSceneKey = SceneKey.Lockscreen,
+                initialSceneKey = Scenes.Lockscreen,
                 authenticationMethod = AuthenticationMethodModel.Pin,
                 isDeviceUnlocked = false,
             )
@@ -650,7 +653,7 @@
     fun collectFalsingSignals_bouncerVisibility() =
         testScope.runTest {
             prepareState(
-                initialSceneKey = SceneKey.Lockscreen,
+                initialSceneKey = Scenes.Lockscreen,
                 authenticationMethod = AuthenticationMethodModel.Pin,
                 isDeviceUnlocked = false,
             )
@@ -658,13 +661,13 @@
             runCurrent()
             verify(falsingCollector).onBouncerHidden()
 
-            sceneInteractor.changeScene(SceneKey.Bouncer, "reason")
+            sceneInteractor.changeScene(Scenes.Bouncer, "reason")
             runCurrent()
             verify(falsingCollector).onBouncerShown()
 
             kosmos.fakeDeviceEntryRepository.setUnlocked(true)
             runCurrent()
-            sceneInteractor.changeScene(SceneKey.Gone, "reason")
+            sceneInteractor.changeScene(Scenes.Gone, "reason")
             runCurrent()
             verify(falsingCollector, times(2)).onBouncerHidden()
         }
@@ -675,7 +678,7 @@
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
 
             prepareState(
-                initialSceneKey = SceneKey.Lockscreen,
+                initialSceneKey = Scenes.Lockscreen,
                 authenticationMethod = AuthenticationMethodModel.Pin,
                 isDeviceUnlocked = false,
             )
@@ -685,7 +688,7 @@
             kosmos.fakeMobileConnectionsRepository.isAnySimSecure.value = true
             runCurrent()
 
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Bouncer)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Bouncer)
         }
 
     @Test
@@ -695,7 +698,7 @@
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
 
             prepareState(
-                initialSceneKey = SceneKey.Bouncer,
+                initialSceneKey = Scenes.Bouncer,
                 authenticationMethod = AuthenticationMethodModel.Pin,
                 isDeviceUnlocked = false,
             )
@@ -704,7 +707,7 @@
             kosmos.fakeMobileConnectionsRepository.isAnySimSecure.value = false
             runCurrent()
 
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
         }
 
     @Test
@@ -714,7 +717,7 @@
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
 
             prepareState(
-                initialSceneKey = SceneKey.Lockscreen,
+                initialSceneKey = Scenes.Lockscreen,
                 authenticationMethod = AuthenticationMethodModel.None,
                 isDeviceUnlocked = true,
                 isLockscreenEnabled = false,
@@ -724,7 +727,7 @@
             kosmos.fakeMobileConnectionsRepository.isAnySimSecure.value = false
             runCurrent()
 
-            assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
+            assertThat(currentSceneKey).isEqualTo(Scenes.Gone)
         }
 
     @Test
@@ -734,9 +737,9 @@
             val transitionStateFlow =
                 prepareState(
                     isDeviceUnlocked = true,
-                    initialSceneKey = SceneKey.Gone,
+                    initialSceneKey = Scenes.Gone,
                 )
-            assertThat(currentDesiredSceneKey).isEqualTo(SceneKey.Gone)
+            assertThat(currentDesiredSceneKey).isEqualTo(Scenes.Gone)
             verify(windowController, never()).setNotificationShadeFocusable(anyBoolean())
 
             underTest.start()
@@ -744,11 +747,11 @@
             verify(windowController, times(1)).setNotificationShadeFocusable(false)
 
             fakeSceneDataSource.pause()
-            sceneInteractor.changeScene(SceneKey.Shade, "reason")
+            sceneInteractor.changeScene(Scenes.Shade, "reason")
             transitionStateFlow.value =
                 ObservableTransitionState.Transition(
-                    fromScene = SceneKey.Gone,
-                    toScene = SceneKey.Shade,
+                    fromScene = Scenes.Gone,
+                    toScene = Scenes.Shade,
                     progress = flowOf(0.5f),
                     isInitiatedByUserInput = false,
                     isUserInputOngoing = flowOf(false),
@@ -756,17 +759,17 @@
             runCurrent()
             verify(windowController, times(1)).setNotificationShadeFocusable(false)
 
-            fakeSceneDataSource.unpause(expectedScene = SceneKey.Shade)
-            transitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Shade)
+            fakeSceneDataSource.unpause(expectedScene = Scenes.Shade)
+            transitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Shade)
             runCurrent()
             verify(windowController, times(1)).setNotificationShadeFocusable(true)
 
             fakeSceneDataSource.pause()
-            sceneInteractor.changeScene(SceneKey.Gone, "reason")
+            sceneInteractor.changeScene(Scenes.Gone, "reason")
             transitionStateFlow.value =
                 ObservableTransitionState.Transition(
-                    fromScene = SceneKey.Shade,
-                    toScene = SceneKey.Gone,
+                    fromScene = Scenes.Shade,
+                    toScene = Scenes.Gone,
                     progress = flowOf(0.5f),
                     isInitiatedByUserInput = false,
                     isUserInputOngoing = flowOf(false),
@@ -774,8 +777,8 @@
             runCurrent()
             verify(windowController, times(1)).setNotificationShadeFocusable(true)
 
-            fakeSceneDataSource.unpause(expectedScene = SceneKey.Gone)
-            transitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Gone)
+            fakeSceneDataSource.unpause(expectedScene = Scenes.Gone)
+            transitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Gone)
             runCurrent()
             verify(windowController, times(2)).setNotificationShadeFocusable(false)
         }
@@ -785,7 +788,7 @@
         testScope.runTest {
             val transitionStateFlow =
                 prepareState(
-                    initialSceneKey = SceneKey.Lockscreen,
+                    initialSceneKey = Scenes.Lockscreen,
                 )
             underTest.start()
             runCurrent()
@@ -794,7 +797,7 @@
             clearInvocations(centralSurfaces)
             emulateSceneTransition(
                 transitionStateFlow = transitionStateFlow,
-                toScene = SceneKey.Bouncer,
+                toScene = Scenes.Bouncer,
                 verifyBeforeTransition = {
                     verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
                 },
@@ -813,7 +816,7 @@
             clearInvocations(centralSurfaces)
             emulateSceneTransition(
                 transitionStateFlow = transitionStateFlow,
-                toScene = SceneKey.Lockscreen,
+                toScene = Scenes.Lockscreen,
                 verifyBeforeTransition = {
                     verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
                 },
@@ -832,7 +835,7 @@
             clearInvocations(centralSurfaces)
             emulateSceneTransition(
                 transitionStateFlow = transitionStateFlow,
-                toScene = SceneKey.Shade,
+                toScene = Scenes.Shade,
                 verifyBeforeTransition = {
                     verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
                 },
@@ -851,7 +854,7 @@
             clearInvocations(centralSurfaces)
             emulateSceneTransition(
                 transitionStateFlow = transitionStateFlow,
-                toScene = SceneKey.Lockscreen,
+                toScene = Scenes.Lockscreen,
                 verifyBeforeTransition = {
                     verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
                 },
@@ -870,7 +873,7 @@
             clearInvocations(centralSurfaces)
             emulateSceneTransition(
                 transitionStateFlow = transitionStateFlow,
-                toScene = SceneKey.QuickSettings,
+                toScene = Scenes.QuickSettings,
                 verifyBeforeTransition = {
                     verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
                 },
@@ -889,7 +892,7 @@
             val transitionStateFlow =
                 prepareState(
                     isDeviceUnlocked = true,
-                    initialSceneKey = SceneKey.Gone,
+                    initialSceneKey = Scenes.Gone,
                 )
             underTest.start()
             verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
@@ -897,7 +900,7 @@
             clearInvocations(centralSurfaces)
             emulateSceneTransition(
                 transitionStateFlow = transitionStateFlow,
-                toScene = SceneKey.Bouncer,
+                toScene = Scenes.Bouncer,
                 verifyBeforeTransition = {
                     verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
                 },
@@ -912,7 +915,7 @@
             clearInvocations(centralSurfaces)
             emulateSceneTransition(
                 transitionStateFlow = transitionStateFlow,
-                toScene = SceneKey.Lockscreen,
+                toScene = Scenes.Lockscreen,
                 verifyBeforeTransition = {
                     verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
                 },
@@ -927,7 +930,7 @@
             clearInvocations(centralSurfaces)
             emulateSceneTransition(
                 transitionStateFlow = transitionStateFlow,
-                toScene = SceneKey.Shade,
+                toScene = Scenes.Shade,
                 verifyBeforeTransition = {
                     verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
                 },
@@ -942,7 +945,7 @@
             clearInvocations(centralSurfaces)
             emulateSceneTransition(
                 transitionStateFlow = transitionStateFlow,
-                toScene = SceneKey.Lockscreen,
+                toScene = Scenes.Lockscreen,
                 verifyBeforeTransition = {
                     verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
                 },
@@ -957,7 +960,7 @@
             clearInvocations(centralSurfaces)
             emulateSceneTransition(
                 transitionStateFlow = transitionStateFlow,
-                toScene = SceneKey.QuickSettings,
+                toScene = Scenes.QuickSettings,
                 verifyBeforeTransition = {
                     verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
                 },
@@ -970,6 +973,20 @@
             )
         }
 
+    @Test
+    fun respondToFalsingDetections() =
+        testScope.runTest {
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            val transitionStateFlow = prepareState()
+            underTest.start()
+            emulateSceneTransition(transitionStateFlow, toScene = Scenes.Bouncer)
+            assertThat(currentScene).isNotEqualTo(Scenes.Lockscreen)
+
+            kosmos.falsingManager.sendFalsingBelief()
+
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+        }
+
     private fun TestScope.emulateSceneTransition(
         transitionStateFlow: MutableStateFlow<ObservableTransitionState>,
         toScene: SceneKey,
@@ -1017,7 +1034,7 @@
             }
         }
 
-        check(initialSceneKey != SceneKey.Gone || isDeviceUnlocked) {
+        check(initialSceneKey != Scenes.Gone || isDeviceUnlocked) {
             "Cannot start on the Gone scene and have the device be locked at the same time."
         }
 
@@ -1027,7 +1044,7 @@
         runCurrent()
         val transitionStateFlow =
             MutableStateFlow<ObservableTransitionState>(
-                ObservableTransitionState.Idle(SceneKey.Lockscreen)
+                ObservableTransitionState.Idle(Scenes.Lockscreen)
             )
         sceneInteractor.setTransitionState(transitionStateFlow)
         initialSceneKey?.let {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegatorTest.kt
index ed4b1e6..32c0172 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegatorTest.kt
@@ -53,9 +53,9 @@
         testScope.runTest {
             val currentScene by collectLastValue(underTest.currentScene)
             underTest.setDelegate(null)
-            assertThat(currentScene).isNotEqualTo(SceneKey.Bouncer)
+            assertThat(currentScene).isNotEqualTo(Scenes.Bouncer)
 
-            underTest.changeScene(toScene = SceneKey.Bouncer)
+            underTest.changeScene(toScene = Scenes.Bouncer)
 
             assertThat(currentScene).isEqualTo(initialSceneKey)
         }
@@ -71,11 +71,11 @@
     fun currentScene_withDelegate_changesScenes() =
         testScope.runTest {
             val currentScene by collectLastValue(underTest.currentScene)
-            assertThat(currentScene).isNotEqualTo(SceneKey.Bouncer)
+            assertThat(currentScene).isNotEqualTo(Scenes.Bouncer)
 
-            underTest.changeScene(toScene = SceneKey.Bouncer)
+            underTest.changeScene(toScene = Scenes.Bouncer)
 
-            assertThat(currentScene).isEqualTo(SceneKey.Bouncer)
+            assertThat(currentScene).isEqualTo(Scenes.Bouncer)
         }
 
     @Test
@@ -83,8 +83,8 @@
         testScope.runTest {
             val currentScene by collectLastValue(underTest.currentScene)
 
-            fakeSceneDataSource.changeScene(toScene = SceneKey.Bouncer)
+            fakeSceneDataSource.changeScene(toScene = Scenes.Bouncer)
 
-            assertThat(currentScene).isEqualTo(SceneKey.Bouncer)
+            assertThat(currentScene).isEqualTo(Scenes.Bouncer)
         }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
index ffbdafe..7b0127e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
@@ -14,10 +14,9 @@
  * limitations under the License.
  */
 
-@file:OptIn(ExperimentalCoroutinesApi::class)
-
 package com.android.systemui.scene.ui.viewmodel
 
+import android.view.MotionEvent
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -31,13 +30,13 @@
 import com.android.systemui.scene.sceneContainerConfig
 import com.android.systemui.scene.sceneKeys
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.shared.model.fakeSceneDataSource
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
-import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -50,7 +49,7 @@
 
     private val kosmos = testKosmos()
     private val testScope by lazy { kosmos.testScope }
-    private val interactor by lazy { kosmos.sceneInteractor }
+    private val sceneInteractor by lazy { kosmos.sceneInteractor }
     private val fakeSceneDataSource = kosmos.fakeSceneDataSource
     private val sceneContainerConfig = kosmos.sceneContainerConfig
     private val falsingManager = kosmos.fakeFalsingManager
@@ -62,7 +61,7 @@
         kosmos.fakeSceneContainerFlags.enabled = true
         underTest =
             SceneContainerViewModel(
-                sceneInteractor = interactor,
+                sceneInteractor = sceneInteractor,
                 falsingInteractor = kosmos.falsingInteractor,
                 powerInteractor = kosmos.powerInteractor,
             )
@@ -74,10 +73,10 @@
             val isVisible by collectLastValue(underTest.isVisible)
             assertThat(isVisible).isTrue()
 
-            interactor.setVisible(false, "reason")
+            sceneInteractor.setVisible(false, "reason")
             assertThat(isVisible).isFalse()
 
-            interactor.setVisible(true, "reason")
+            sceneInteractor.setVisible(true, "reason")
             assertThat(isVisible).isTrue()
         }
 
@@ -90,20 +89,20 @@
     fun sceneTransition() =
         testScope.runTest {
             val currentScene by collectLastValue(underTest.currentScene)
-            assertThat(currentScene).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
 
-            fakeSceneDataSource.changeScene(SceneKey.Shade)
+            fakeSceneDataSource.changeScene(Scenes.Shade)
 
-            assertThat(currentScene).isEqualTo(SceneKey.Shade)
+            assertThat(currentScene).isEqualTo(Scenes.Shade)
         }
 
     @Test
     fun canChangeScene_whenAllowed_switchingFromGone_returnsTrue() =
         testScope.runTest {
             val currentScene by collectLastValue(underTest.currentScene)
-            fakeSceneDataSource.changeScene(toScene = SceneKey.Gone)
+            fakeSceneDataSource.changeScene(toScene = Scenes.Gone)
             runCurrent()
-            assertThat(currentScene).isEqualTo(SceneKey.Gone)
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
 
             sceneContainerConfig.sceneKeys
                 .filter { it != currentScene }
@@ -118,9 +117,9 @@
     fun canChangeScene_whenAllowed_switchingFromLockscreen_returnsTrue() =
         testScope.runTest {
             val currentScene by collectLastValue(underTest.currentScene)
-            fakeSceneDataSource.changeScene(toScene = SceneKey.Lockscreen)
+            fakeSceneDataSource.changeScene(toScene = Scenes.Lockscreen)
             runCurrent()
-            assertThat(currentScene).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
 
             sceneContainerConfig.sceneKeys
                 .filter { it != currentScene }
@@ -136,15 +135,15 @@
         testScope.runTest {
             falsingManager.setIsFalseTouch(true)
             val currentScene by collectLastValue(underTest.currentScene)
-            fakeSceneDataSource.changeScene(toScene = SceneKey.Lockscreen)
+            fakeSceneDataSource.changeScene(toScene = Scenes.Lockscreen)
             runCurrent()
-            assertThat(currentScene).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
 
             sceneContainerConfig.sceneKeys
                 .filter { it != currentScene }
                 .filter {
                     // Moving to the Communal scene is not currently falsing protected.
-                    it != SceneKey.Communal
+                    it != Scenes.Communal
                 }
                 .forEach { toScene ->
                     assertWithMessage("Protected scene $toScene not properly protected")
@@ -158,14 +157,14 @@
         testScope.runTest {
             falsingManager.setIsFalseTouch(true)
             val currentScene by collectLastValue(underTest.currentScene)
-            fakeSceneDataSource.changeScene(toScene = SceneKey.Lockscreen)
+            fakeSceneDataSource.changeScene(toScene = Scenes.Lockscreen)
             runCurrent()
-            assertThat(currentScene).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
 
             sceneContainerConfig.sceneKeys
                 .filter {
                     // Moving to the Communal scene is not currently falsing protected.
-                    it == SceneKey.Communal
+                    it == Scenes.Communal
                 }
                 .forEach { toScene ->
                     assertWithMessage("Unprotected scene $toScene is incorrectly protected")
@@ -179,9 +178,9 @@
         testScope.runTest {
             falsingManager.setIsFalseTouch(true)
             val currentScene by collectLastValue(underTest.currentScene)
-            fakeSceneDataSource.changeScene(toScene = SceneKey.Gone)
+            fakeSceneDataSource.changeScene(toScene = Scenes.Gone)
             runCurrent()
-            assertThat(currentScene).isEqualTo(SceneKey.Gone)
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
 
             sceneContainerConfig.sceneKeys
                 .filter { it != currentScene }
@@ -199,4 +198,20 @@
             underTest.onMotionEvent(mock())
             assertThat(kosmos.fakePowerRepository.userTouchRegistered).isTrue()
         }
+
+    @Test
+    fun remoteUserInteraction_keepsContainerVisible() =
+        testScope.runTest {
+            sceneInteractor.setVisible(false, "reason")
+            val isVisible by collectLastValue(underTest.isVisible)
+            assertThat(isVisible).isFalse()
+            sceneInteractor.onRemoteUserInteractionStarted("reason")
+            assertThat(isVisible).isTrue()
+
+            underTest.onMotionEvent(
+                mock { whenever(actionMasked).thenReturn(MotionEvent.ACTION_UP) }
+            )
+
+            assertThat(isVisible).isFalse()
+        }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeControllerSceneImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeControllerSceneImplTest.kt
index ec424b0..d3fa360 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeControllerSceneImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ShadeControllerSceneImplTest.kt
@@ -18,6 +18,8 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
 import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
@@ -28,8 +30,7 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.statusbar.CommandQueue
@@ -87,7 +88,7 @@
             runCurrent()
 
             // THEN the shade remains collapsed and the post-collapse action ran
-            assertThat(sceneInteractor.currentScene.value).isEqualTo(SceneKey.Gone)
+            assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Gone)
             verify(testRunnable, times(1)).run()
         }
 
@@ -105,7 +106,7 @@
             runCurrent()
 
             // THEN the shade remains expanded and the post-collapse action did not run
-            assertThat(sceneInteractor.currentScene.value).isEqualTo(SceneKey.Shade)
+            assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Shade)
             assertThat(shadeInteractor.isAnyFullyExpanded.value).isTrue()
             verify(testRunnable, never()).run()
         }
@@ -122,7 +123,7 @@
             runCurrent()
 
             // THEN the shade collapses back to lockscreen and the post-collapse action ran
-            assertThat(sceneInteractor.currentScene.value).isEqualTo(SceneKey.Lockscreen)
+            assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Lockscreen)
         }
 
     @Test
@@ -137,7 +138,7 @@
             runCurrent()
 
             // THEN the shade collapses back to lockscreen and the post-collapse action ran
-            assertThat(sceneInteractor.currentScene.value).isEqualTo(SceneKey.Gone)
+            assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Gone)
         }
 
     @Test
@@ -181,21 +182,21 @@
     private fun setDeviceEntered(isEntered: Boolean) {
         setScene(
             if (isEntered) {
-                SceneKey.Gone
+                Scenes.Gone
             } else {
-                SceneKey.Lockscreen
+                Scenes.Lockscreen
             }
         )
         assertThat(deviceEntryInteractor.isDeviceEntered.value).isEqualTo(isEntered)
     }
 
     private fun setCollapsed() {
-        setScene(SceneKey.Gone)
+        setScene(Scenes.Gone)
         assertThat(shadeInteractor.isAnyExpanded.value).isFalse()
     }
 
     private fun setShadeFullyExpanded() {
-        setScene(SceneKey.Shade)
+        setScene(Scenes.Shade)
         assertThat(shadeInteractor.isAnyFullyExpanded.value).isTrue()
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt
index 1ef07fa..bb40591 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt
@@ -18,12 +18,12 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.kosmos.testScope
 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.scene.shared.model.Scenes
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -53,8 +53,8 @@
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
-                        fromScene = SceneKey.QuickSettings,
-                        toScene = SceneKey.Shade,
+                        fromScene = Scenes.QuickSettings,
+                        toScene = Scenes.Shade,
                         progress = MutableStateFlow(.1f),
                         isInitiatedByUserInput = false,
                         isUserInputOngoing = flowOf(false),
@@ -76,8 +76,8 @@
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
-                        fromScene = SceneKey.QuickSettings,
-                        toScene = SceneKey.Gone,
+                        fromScene = Scenes.QuickSettings,
+                        toScene = Scenes.Gone,
                         progress = MutableStateFlow(.1f),
                         isInitiatedByUserInput = false,
                         isUserInputOngoing = flowOf(false),
@@ -99,8 +99,8 @@
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
-                        fromScene = SceneKey.QuickSettings,
-                        toScene = SceneKey.Gone,
+                        fromScene = Scenes.QuickSettings,
+                        toScene = Scenes.Gone,
                         progress = MutableStateFlow(.1f),
                         isInitiatedByUserInput = false,
                         isUserInputOngoing = flowOf(true),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImplTest.kt
index ec4da04..b662133 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImplTest.kt
@@ -19,13 +19,14 @@
 import android.content.applicationContext
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shared.recents.utilities.Utilities
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
@@ -56,45 +57,45 @@
     @Test
     fun animateCollapseQs_notOnQs() =
         testScope.runTest {
-            setScene(SceneKey.Shade)
+            setScene(Scenes.Shade)
             underTest.animateCollapseQs(true)
             runCurrent()
-            assertThat(sceneInteractor.currentScene.value).isEqualTo(SceneKey.Shade)
+            assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Shade)
         }
 
     @Test
     fun animateCollapseQs_fullyCollapse_entered() =
         testScope.runTest {
             enterDevice()
-            setScene(SceneKey.QuickSettings)
+            setScene(Scenes.QuickSettings)
             underTest.animateCollapseQs(true)
             runCurrent()
-            assertThat(sceneInteractor.currentScene.value).isEqualTo(SceneKey.Gone)
+            assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Gone)
         }
 
     @Test
     fun animateCollapseQs_fullyCollapse_locked() =
         testScope.runTest {
             deviceEntryRepository.setUnlocked(false)
-            setScene(SceneKey.QuickSettings)
+            setScene(Scenes.QuickSettings)
             underTest.animateCollapseQs(true)
             runCurrent()
-            assertThat(sceneInteractor.currentScene.value).isEqualTo(SceneKey.Lockscreen)
+            assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Lockscreen)
         }
 
     @Test
     fun animateCollapseQs_notFullyCollapse() =
         testScope.runTest {
-            setScene(SceneKey.QuickSettings)
+            setScene(Scenes.QuickSettings)
             underTest.animateCollapseQs(false)
             runCurrent()
-            assertThat(sceneInteractor.currentScene.value).isEqualTo(SceneKey.Shade)
+            assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Shade)
         }
 
     private fun enterDevice() {
         deviceEntryRepository.setUnlocked(true)
         testScope.runCurrent()
-        setScene(SceneKey.Gone)
+        setScene(Scenes.Gone)
     }
 
     private fun setScene(key: SceneKey) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
index bf136cd..4cd2c30 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
@@ -18,6 +18,7 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
 import com.android.systemui.coroutines.collectLastValue
@@ -27,8 +28,7 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.res.R
 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.scene.shared.model.Scenes
 import com.android.systemui.testKosmos
 import com.android.systemui.user.data.repository.userRepository
 import com.google.common.truth.Truth
@@ -67,8 +67,8 @@
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
-                        fromScene = SceneKey.QuickSettings,
-                        toScene = SceneKey.Shade,
+                        fromScene = Scenes.QuickSettings,
+                        toScene = Scenes.Shade,
                         progress = MutableStateFlow(.3f),
                         isInitiatedByUserInput = false,
                         isUserInputOngoing = flowOf(false),
@@ -96,8 +96,8 @@
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
-                        fromScene = SceneKey.QuickSettings,
-                        toScene = SceneKey.Shade,
+                        fromScene = Scenes.QuickSettings,
+                        toScene = Scenes.Shade,
                         progress = progress,
                         isInitiatedByUserInput = false,
                         isUserInputOngoing = flowOf(false),
@@ -120,8 +120,8 @@
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
-                        fromScene = SceneKey.QuickSettings,
-                        toScene = SceneKey.Shade,
+                        fromScene = Scenes.QuickSettings,
+                        toScene = Scenes.Shade,
                         progress = MutableStateFlow(.3f),
                         isInitiatedByUserInput = false,
                         isUserInputOngoing = flowOf(false),
@@ -143,7 +143,7 @@
             keyguardRepository.setStatusBarState(StatusBarState.SHADE)
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
-                    ObservableTransitionState.Idle(SceneKey.Shade)
+                    ObservableTransitionState.Idle(Scenes.Shade)
                 )
             sceneInteractor.setTransitionState(transitionState)
             runCurrent()
@@ -161,7 +161,7 @@
             keyguardRepository.setStatusBarState(StatusBarState.SHADE)
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
-                    ObservableTransitionState.Idle(SceneKey.QuickSettings)
+                    ObservableTransitionState.Idle(Scenes.QuickSettings)
                 )
             sceneInteractor.setTransitionState(transitionState)
             runCurrent()
@@ -174,7 +174,7 @@
     fun lockscreenShadeExpansion_idle_onScene() =
         testComponent.runTest {
             // GIVEN an expansion flow based on transitions to and from a scene
-            val key = SceneKey.Shade
+            val key = Scenes.Shade
             val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
             val expansionAmount by collectLastValue(expansion)
 
@@ -191,13 +191,13 @@
     fun lockscreenShadeExpansion_idle_onDifferentScene() =
         testComponent.runTest {
             // GIVEN an expansion flow based on transitions to and from a scene
-            val expansion = underTest.sceneBasedExpansion(sceneInteractor, SceneKey.Shade)
+            val expansion = underTest.sceneBasedExpansion(sceneInteractor, Scenes.Shade)
             val expansionAmount by collectLastValue(expansion)
 
             // WHEN transition state is idle on a different scene
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
-                    ObservableTransitionState.Idle(SceneKey.Lockscreen)
+                    ObservableTransitionState.Idle(Scenes.Lockscreen)
                 )
             sceneInteractor.setTransitionState(transitionState)
 
@@ -209,7 +209,7 @@
     fun lockscreenShadeExpansion_transitioning_toScene() =
         testComponent.runTest {
             // GIVEN an expansion flow based on transitions to and from a scene
-            val key = SceneKey.QuickSettings
+            val key = Scenes.QuickSettings
             val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
             val expansionAmount by collectLastValue(expansion)
 
@@ -218,7 +218,7 @@
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
-                        fromScene = SceneKey.Lockscreen,
+                        fromScene = Scenes.Lockscreen,
                         toScene = key,
                         progress = progress,
                         isInitiatedByUserInput = false,
@@ -247,7 +247,7 @@
     fun lockscreenShadeExpansion_transitioning_fromScene() =
         testComponent.runTest {
             // GIVEN an expansion flow based on transitions to and from a scene
-            val key = SceneKey.QuickSettings
+            val key = Scenes.QuickSettings
             val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
             val expansionAmount by collectLastValue(expansion)
 
@@ -257,7 +257,7 @@
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
                         fromScene = key,
-                        toScene = SceneKey.Lockscreen,
+                        toScene = Scenes.Lockscreen,
                         progress = progress,
                         isInitiatedByUserInput = false,
                         isUserInputOngoing = flowOf(false),
@@ -290,8 +290,8 @@
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
-                        fromScene = SceneKey.Gone,
-                        toScene = SceneKey.QuickSettings,
+                        fromScene = Scenes.Gone,
+                        toScene = Scenes.QuickSettings,
                         progress = MutableStateFlow(.1f),
                         isInitiatedByUserInput = false,
                         isUserInputOngoing = flowOf(false),
@@ -313,8 +313,8 @@
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
-                        fromScene = SceneKey.Shade,
-                        toScene = SceneKey.QuickSettings,
+                        fromScene = Scenes.Shade,
+                        toScene = Scenes.QuickSettings,
                         progress = MutableStateFlow(.1f),
                         isInitiatedByUserInput = false,
                         isUserInputOngoing = flowOf(false),
@@ -331,7 +331,7 @@
     fun lockscreenShadeExpansion_transitioning_toAndFromDifferentScenes() =
         testComponent.runTest {
             // GIVEN an expansion flow based on transitions to and from a scene
-            val expansion = underTest.sceneBasedExpansion(sceneInteractor, SceneKey.QuickSettings)
+            val expansion = underTest.sceneBasedExpansion(sceneInteractor, Scenes.QuickSettings)
             val expansionAmount by collectLastValue(expansion)
 
             // WHEN transition state is starting to between different scenes
@@ -339,8 +339,8 @@
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
-                        fromScene = SceneKey.Lockscreen,
-                        toScene = SceneKey.Shade,
+                        fromScene = Scenes.Lockscreen,
+                        toScene = Scenes.Shade,
                         progress = progress,
                         isInitiatedByUserInput = false,
                         isUserInputOngoing = flowOf(false),
@@ -368,7 +368,7 @@
     fun userInteracting_idle() =
         testComponent.runTest {
             // GIVEN an interacting flow based on transitions to and from a scene
-            val key = SceneKey.Shade
+            val key = Scenes.Shade
             val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
             val interacting by collectLastValue(interactingFlow)
 
@@ -385,7 +385,7 @@
     fun userInteracting_transitioning_toScene_programmatic() =
         testComponent.runTest {
             // GIVEN an interacting flow based on transitions to and from a scene
-            val key = SceneKey.QuickSettings
+            val key = Scenes.QuickSettings
             val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
             val interacting by collectLastValue(interactingFlow)
 
@@ -394,7 +394,7 @@
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
-                        fromScene = SceneKey.Lockscreen,
+                        fromScene = Scenes.Lockscreen,
                         toScene = key,
                         progress = progress,
                         isInitiatedByUserInput = false,
@@ -423,7 +423,7 @@
     fun userInteracting_transitioning_toScene_userInputDriven() =
         testComponent.runTest {
             // GIVEN an interacting flow based on transitions to and from a scene
-            val key = SceneKey.QuickSettings
+            val key = Scenes.QuickSettings
             val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
             val interacting by collectLastValue(interactingFlow)
 
@@ -432,7 +432,7 @@
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
-                        fromScene = SceneKey.Lockscreen,
+                        fromScene = Scenes.Lockscreen,
                         toScene = key,
                         progress = progress,
                         isInitiatedByUserInput = true,
@@ -461,7 +461,7 @@
     fun userInteracting_transitioning_fromScene_programmatic() =
         testComponent.runTest {
             // GIVEN an interacting flow based on transitions to and from a scene
-            val key = SceneKey.QuickSettings
+            val key = Scenes.QuickSettings
             val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
             val interacting by collectLastValue(interactingFlow)
 
@@ -471,7 +471,7 @@
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
                         fromScene = key,
-                        toScene = SceneKey.Lockscreen,
+                        toScene = Scenes.Lockscreen,
                         progress = progress,
                         isInitiatedByUserInput = false,
                         isUserInputOngoing = flowOf(false),
@@ -499,7 +499,7 @@
     fun userInteracting_transitioning_fromScene_userInputDriven() =
         testComponent.runTest {
             // GIVEN an interacting flow based on transitions to and from a scene
-            val key = SceneKey.QuickSettings
+            val key = Scenes.QuickSettings
             val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
             val interacting by collectLastValue(interactingFlow)
 
@@ -509,7 +509,7 @@
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
                         fromScene = key,
-                        toScene = SceneKey.Lockscreen,
+                        toScene = Scenes.Lockscreen,
                         progress = progress,
                         isInitiatedByUserInput = true,
                         isUserInputOngoing = flowOf(false),
@@ -537,7 +537,7 @@
     fun userInteracting_transitioning_toAndFromDifferentScenes() =
         testComponent.runTest {
             // GIVEN an interacting flow based on transitions to and from a scene
-            val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, SceneKey.Shade)
+            val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, Scenes.Shade)
             val interacting by collectLastValue(interactingFlow)
 
             // WHEN transition state is starting to between different scenes
@@ -545,8 +545,8 @@
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
-                        fromScene = SceneKey.Lockscreen,
-                        toScene = SceneKey.QuickSettings,
+                        fromScene = Scenes.Lockscreen,
+                        toScene = Scenes.QuickSettings,
                         progress = MutableStateFlow(0f),
                         isInitiatedByUserInput = true,
                         isUserInputOngoing = flowOf(false),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
index d655ade..853b00d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
@@ -30,7 +30,7 @@
 import com.android.systemui.media.controls.domain.pipeline.MediaDataManager
 import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter
 import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.domain.interactor.privacyChipInteractor
 import com.android.systemui.shade.domain.interactor.shadeHeaderClockInteractor
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModel
@@ -125,7 +125,7 @@
             )
             kosmos.fakeDeviceEntryRepository.setUnlocked(false)
 
-            assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Lockscreen)
+            assertThat(upTransitionSceneKey).isEqualTo(Scenes.Lockscreen)
         }
 
     @Test
@@ -137,7 +137,7 @@
             )
             kosmos.fakeDeviceEntryRepository.setUnlocked(true)
 
-            assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
+            assertThat(upTransitionSceneKey).isEqualTo(Scenes.Gone)
         }
 
     @Test
@@ -148,9 +148,9 @@
             kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
                 AuthenticationMethodModel.None
             )
-            sceneInteractor.changeScene(SceneKey.Lockscreen, "reason")
+            sceneInteractor.changeScene(Scenes.Lockscreen, "reason")
 
-            assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Lockscreen)
+            assertThat(upTransitionSceneKey).isEqualTo(Scenes.Lockscreen)
         }
 
     @Test
@@ -163,9 +163,9 @@
                 AuthenticationMethodModel.None
             )
             runCurrent()
-            sceneInteractor.changeScene(SceneKey.Gone, "reason")
+            sceneInteractor.changeScene(Scenes.Gone, "reason")
 
-            assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
+            assertThat(upTransitionSceneKey).isEqualTo(Scenes.Gone)
         }
 
     @Test
@@ -206,7 +206,7 @@
 
             underTest.onContentClicked()
 
-            assertThat(currentScene).isEqualTo(SceneKey.Gone)
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
         }
 
     @Test
@@ -221,7 +221,7 @@
 
             underTest.onContentClicked()
 
-            assertThat(currentScene).isEqualTo(SceneKey.Bouncer)
+            assertThat(currentScene).isEqualTo(Scenes.Bouncer)
         }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
index efd8f00..47918c8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
@@ -20,6 +20,7 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.NotificationContainerBounds
 import com.android.systemui.coroutines.collectLastValue
@@ -28,8 +29,7 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.shared.model.fakeSceneDataSource
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationStackAppearanceViewModel
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModel
@@ -92,19 +92,19 @@
         testScope.runTest {
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
-                    ObservableTransitionState.Idle(scene = SceneKey.Gone)
+                    ObservableTransitionState.Idle(scene = Scenes.Gone)
                 )
             sceneInteractor.setTransitionState(transitionState)
             val expandFraction by collectLastValue(appearanceViewModel.expandFraction)
             assertThat(expandFraction).isEqualTo(0f)
 
             fakeSceneDataSource.pause()
-            sceneInteractor.changeScene(SceneKey.Shade, "reason")
+            sceneInteractor.changeScene(Scenes.Shade, "reason")
             val transitionProgress = MutableStateFlow(0f)
             transitionState.value =
                 ObservableTransitionState.Transition(
-                    fromScene = SceneKey.Gone,
-                    toScene = SceneKey.Shade,
+                    fromScene = Scenes.Gone,
+                    toScene = Scenes.Shade,
                     progress = transitionProgress,
                     isInitiatedByUserInput = false,
                     isUserInputOngoing = flowOf(false),
@@ -117,7 +117,7 @@
                 assertThat(expandFraction).isWithin(0.01f).of(progress)
             }
 
-            fakeSceneDataSource.unpause(expectedScene = SceneKey.Shade)
+            fakeSceneDataSource.unpause(expectedScene = Scenes.Shade)
             assertThat(expandFraction).isWithin(0.01f).of(1f)
         }
 
@@ -126,7 +126,7 @@
         testScope.runTest {
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
-                    ObservableTransitionState.Idle(scene = SceneKey.Lockscreen)
+                    ObservableTransitionState.Idle(scene = Scenes.Lockscreen)
                 )
             sceneInteractor.setTransitionState(transitionState)
             val expandFraction by collectLastValue(appearanceViewModel.expandFraction)
@@ -138,19 +138,19 @@
         testScope.runTest {
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
-                    ObservableTransitionState.Idle(scene = SceneKey.Shade)
+                    ObservableTransitionState.Idle(scene = Scenes.Shade)
                 )
             sceneInteractor.setTransitionState(transitionState)
             val expandFraction by collectLastValue(appearanceViewModel.expandFraction)
             assertThat(expandFraction).isEqualTo(1f)
 
             fakeSceneDataSource.pause()
-            sceneInteractor.changeScene(SceneKey.QuickSettings, "reason")
+            sceneInteractor.changeScene(Scenes.QuickSettings, "reason")
             val transitionProgress = MutableStateFlow(0f)
             transitionState.value =
                 ObservableTransitionState.Transition(
-                    fromScene = SceneKey.Shade,
-                    toScene = SceneKey.QuickSettings,
+                    fromScene = Scenes.Shade,
+                    toScene = Scenes.QuickSettings,
                     progress = transitionProgress,
                     isInitiatedByUserInput = false,
                     isUserInputOngoing = flowOf(false),
@@ -163,7 +163,7 @@
                 assertThat(expandFraction).isEqualTo(1f)
             }
 
-            fakeSceneDataSource.unpause(expectedScene = SceneKey.QuickSettings)
+            fakeSceneDataSource.unpause(expectedScene = Scenes.QuickSettings)
             assertThat(expandFraction).isEqualTo(1f)
         }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index 0641c61..0de15b8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -21,13 +21,13 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.Flags.FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.NotificationContainerBounds
 import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
 import com.android.systemui.communal.domain.interactor.communalInteractor
-import com.android.systemui.communal.shared.model.CommunalSceneKey
-import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
+import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.flags.Flags
 import com.android.systemui.flags.fakeFeatureFlagsClassic
@@ -47,8 +47,6 @@
 import com.android.systemui.shade.data.repository.shadeRepository
 import com.android.systemui.shade.mockLargeScreenHeaderHelper
 import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
-import com.android.systemui.statusbar.policy.SplitShadeStateController
-import com.android.systemui.statusbar.policy.splitShadeStateController
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.whenever
@@ -68,7 +66,6 @@
 @RunWith(AndroidJUnit4::class)
 class SharedNotificationContainerViewModelTest : SysuiTestCase() {
     val aodBurnInViewModel = mock(AodBurnInViewModel::class.java)
-    val splitShadeStateController = mock(SplitShadeStateController::class.java)
     lateinit var translationYFlow: MutableStateFlow<Float>
 
     val kosmos =
@@ -81,7 +78,6 @@
 
     init {
         kosmos.aodBurnInViewModel = aodBurnInViewModel
-        kosmos.splitShadeStateController = splitShadeStateController
     }
     val testScope = kosmos.testScope
     val configurationRepository = kosmos.fakeConfigurationRepository
@@ -98,7 +94,7 @@
 
     @Before
     fun setUp() {
-        whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())).thenReturn(false)
+        overrideResource(R.bool.config_use_split_notification_shade, false)
         translationYFlow = MutableStateFlow(0f)
         whenever(aodBurnInViewModel.translationY(any())).thenReturn(translationYFlow)
         underTest = kosmos.sharedNotificationContainerViewModel
@@ -107,8 +103,7 @@
     @Test
     fun validateMarginStartInSplitShade() =
         testScope.runTest {
-            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
-                .thenReturn(true)
+            overrideResource(R.bool.config_use_split_notification_shade, true)
             overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
 
             val dimens by collectLastValue(underTest.configurationBasedDimensions)
@@ -121,8 +116,7 @@
     @Test
     fun validateMarginStart() =
         testScope.runTest {
-            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
-                .thenReturn(false)
+            overrideResource(R.bool.config_use_split_notification_shade, false)
             overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
 
             val dimens by collectLastValue(underTest.configurationBasedDimensions)
@@ -137,8 +131,7 @@
         testScope.runTest {
             mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
             whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)
-            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
-                .thenReturn(true)
+            overrideResource(R.bool.config_use_split_notification_shade, true)
             overrideResource(R.bool.config_use_large_screen_shade_header, true)
             overrideResource(R.dimen.large_screen_shade_header_height, 10)
             overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
@@ -156,8 +149,7 @@
         testScope.runTest {
             mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
             whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)
-            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
-                .thenReturn(true)
+            overrideResource(R.bool.config_use_split_notification_shade, true)
             overrideResource(R.bool.config_use_large_screen_shade_header, true)
             overrideResource(R.dimen.large_screen_shade_header_height, 10)
             overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
@@ -172,8 +164,7 @@
     @Test
     fun validatePaddingTop() =
         testScope.runTest {
-            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
-                .thenReturn(false)
+            overrideResource(R.bool.config_use_split_notification_shade, false)
             overrideResource(R.dimen.large_screen_shade_header_height, 10)
             overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
 
@@ -287,8 +278,8 @@
                 )
             )
             val idleTransitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal)
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(CommunalScenes.Communal)
                 )
             communalInteractor.setTransitionState(idleTransitionState)
             runCurrent()
@@ -400,8 +391,8 @@
 
             // Move to glanceable hub
             val idleTransitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal)
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(CommunalScenes.Communal)
                 )
             communalInteractor.setTransitionState(idleTransitionState)
             runCurrent()
@@ -431,8 +422,7 @@
             val bounds by collectLastValue(underTest.bounds)
 
             // When not in split shade
-            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
-                .thenReturn(false)
+            overrideResource(R.bool.config_use_split_notification_shade, false)
             configurationRepository.onAnyConfigurationChange()
             runCurrent()
 
@@ -454,8 +444,7 @@
 
             // When in split shade
             whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)
-            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
-                .thenReturn(true)
+            overrideResource(R.bool.config_use_split_notification_shade, true)
             overrideResource(R.bool.config_use_large_screen_shade_header, true)
             overrideResource(R.dimen.large_screen_shade_header_height, 10)
             overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
@@ -483,8 +472,7 @@
 
             // When in split shade
             whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)
-            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
-                .thenReturn(true)
+            overrideResource(R.bool.config_use_split_notification_shade, true)
             overrideResource(R.bool.config_use_large_screen_shade_header, true)
             overrideResource(R.dimen.large_screen_shade_header_height, 10)
             overrideResource(R.dimen.keyguard_split_shade_top_margin, 50)
@@ -543,8 +531,7 @@
 
             showLockscreen()
 
-            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
-                .thenReturn(false)
+            overrideResource(R.bool.config_use_split_notification_shade, false)
             configurationRepository.onAnyConfigurationChange()
             keyguardInteractor.setNotificationContainerBounds(
                 NotificationContainerBounds(top = 1f, bottom = 2f)
@@ -567,8 +554,7 @@
 
             showLockscreen()
 
-            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
-                .thenReturn(false)
+            overrideResource(R.bool.config_use_split_notification_shade, false)
             configurationRepository.onAnyConfigurationChange()
             keyguardInteractor.setNotificationContainerBounds(
                 NotificationContainerBounds(top = 1f, bottom = 2f)
@@ -604,8 +590,7 @@
             // Show lockscreen with shade expanded
             showLockscreenWithShadeExpanded()
 
-            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
-                .thenReturn(false)
+            overrideResource(R.bool.config_use_split_notification_shade, false)
             configurationRepository.onAnyConfigurationChange()
             keyguardInteractor.setNotificationContainerBounds(
                 NotificationContainerBounds(top = 1f, bottom = 2f)
@@ -701,6 +686,32 @@
             assertThat(fadeIn).isEqualTo(false)
         }
 
+    @Test
+    fun shadeCollapseFadeIn_doesNotRunIfTransitioningToAod() =
+        testScope.runTest {
+            val fadeIn by collectLastValue(underTest.shadeCollapseFadeIn)
+
+            // Start on lockscreen without the shade
+            underTest.setShadeCollapseFadeInComplete(false)
+            showLockscreen()
+            assertThat(fadeIn).isEqualTo(false)
+
+            // ... then the shade expands
+            showLockscreenWithShadeExpanded()
+            assertThat(fadeIn).isEqualTo(false)
+
+            // ... then user hits power to go to AOD
+            keyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.LOCKSCREEN,
+                to = KeyguardState.AOD,
+                testScope,
+            )
+            // ... followed by a shade collapse
+            showLockscreen()
+            // ... does not trigger a fade in
+            assertThat(fadeIn).isEqualTo(false)
+        }
+
     private suspend fun TestScope.showLockscreen() {
         shadeRepository.setLockscreenShadeExpansion(0f)
         shadeRepository.setQsExpansion(0f)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
index c01f1c7..8aa0e3fc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
@@ -35,10 +35,10 @@
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.shade.ShadeController
-import com.android.systemui.shade.ShadeViewController
 import com.android.systemui.shade.data.repository.FakeShadeRepository
 import com.android.systemui.shade.data.repository.ShadeAnimationRepository
 import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorLegacyImpl
+import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.SysuiStatusBarStateController
@@ -76,7 +76,7 @@
     @Mock private lateinit var biometricUnlockController: BiometricUnlockController
     @Mock private lateinit var keyguardViewMediator: KeyguardViewMediator
     @Mock private lateinit var shadeController: ShadeController
-    @Mock private lateinit var shadeViewController: ShadeViewController
+    @Mock private lateinit var commandQueue: CommandQueue
     @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
     @Mock private lateinit var mActivityTransitionAnimator: ActivityTransitionAnimator
     @Mock private lateinit var lockScreenUserManager: NotificationLockscreenUserManager
@@ -105,7 +105,7 @@
                 Lazy { biometricUnlockController },
                 Lazy { keyguardViewMediator },
                 Lazy { shadeController },
-                Lazy { shadeViewController },
+                commandQueue,
                 shadeAnimationInteractor,
                 Lazy { statusBarKeyguardViewManager },
                 Lazy { notifShadeWindowController },
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
index 87d25dd..db4d42f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
@@ -19,8 +19,6 @@
 import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
 
 import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer;
-import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
-import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -41,31 +39,24 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.Person;
-import android.content.Context;
 import android.content.Intent;
-import android.graphics.Region;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.testing.TestableLooper;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.test.filters.SmallTest;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
 
-import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.testing.UiEventLoggerFake;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.res.R;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.settings.FakeGlobalSettings;
-import com.android.systemui.util.settings.GlobalSettings;
 import com.android.systemui.util.time.FakeSystemClock;
-import com.android.systemui.util.time.SystemClock;
 
 import org.junit.Rule;
 import org.junit.Test;
@@ -81,17 +72,13 @@
     @Rule
     public MockitoRule rule = MockitoJUnit.rule();
 
-    private static final String TEST_PACKAGE_NAME = "BaseHeadsUpManagerTest";
-
-    private static final int TEST_TOUCH_ACCEPTANCE_TIME = 200;
-    private static final int TEST_A11Y_AUTO_DISMISS_TIME = 1_000;
+    static final int TEST_TOUCH_ACCEPTANCE_TIME = 200;
+    static final int TEST_A11Y_AUTO_DISMISS_TIME = 1_000;
 
     private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
     private final HeadsUpManagerLogger mLogger = spy(new HeadsUpManagerLogger(logcatLogBuffer()));
     @Mock private AccessibilityManagerWrapper mAccessibilityMgr;
 
-    private static final int TEST_UID = 0;
-
     protected static final int TEST_MINIMUM_DISPLAY_TIME = 400;
     protected static final int TEST_AUTO_DISMISS_TIME = 600;
     protected static final int TEST_STICKY_AUTO_DISMISS_TIME = 800;
@@ -110,143 +97,6 @@
         assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_A11Y_AUTO_DISMISS_TIME);
     }
 
-    private final class TestableHeadsUpManager extends BaseHeadsUpManager {
-
-        private HeadsUpEntry mLastCreatedEntry;
-
-        TestableHeadsUpManager(Context context,
-                HeadsUpManagerLogger logger,
-                DelayableExecutor executor,
-                GlobalSettings globalSettings,
-                SystemClock systemClock,
-                AccessibilityManagerWrapper accessibilityManagerWrapper,
-                UiEventLogger uiEventLogger) {
-            super(context, logger, mockExecutorHandler(executor), globalSettings, systemClock,
-                    executor, accessibilityManagerWrapper, uiEventLogger);
-
-            mTouchAcceptanceDelay = TEST_TOUCH_ACCEPTANCE_TIME;
-            mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
-            mAutoDismissTime = TEST_AUTO_DISMISS_TIME;
-            mStickyForSomeTimeAutoDismissTime = TEST_STICKY_AUTO_DISMISS_TIME;
-
-        }
-
-        @Override
-        protected HeadsUpEntry createHeadsUpEntry() {
-            mLastCreatedEntry = spy(super.createHeadsUpEntry());
-            return mLastCreatedEntry;
-        }
-
-        @Override
-        public int getContentFlag() {
-            return FLAG_CONTENT_VIEW_CONTRACTED;
-        }
-
-        // The following are only implemented by HeadsUpManagerPhone. If you need them, use that.
-        @Override
-        public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void addSwipedOutNotification(@NonNull String key) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void extendHeadsUp() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Nullable
-        @Override
-        public Region getTouchableRegion() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public boolean isHeadsUpGoingAway() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void onExpandingFinished() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public boolean removeNotification(@NonNull String key, boolean releaseImmediately,
-                boolean animate) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void setAnimationStateHandler(@NonNull AnimationStateHandler handler) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void setRemoteInputActive(@NonNull NotificationEntry entry,
-                boolean remoteInputActive) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void setTrackingHeadsUp(boolean tracking) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public boolean shouldSwallowClick(@NonNull String key) {
-            throw new UnsupportedOperationException();
-        }
-    }
-
-    protected StatusBarNotification createSbn(int id, Notification n) {
-        return new StatusBarNotification(
-                TEST_PACKAGE_NAME /* pkg */,
-                TEST_PACKAGE_NAME,
-                id,
-                null /* tag */,
-                TEST_UID,
-                0 /* initialPid */,
-                n,
-                new UserHandle(ActivityManager.getCurrentUser()),
-                null /* overrideGroupKey */,
-                0 /* postTime */);
-    }
-
-    protected StatusBarNotification createSbn(int id, Notification.Builder n) {
-        return createSbn(id, n.build());
-    }
-
-    protected StatusBarNotification createSbn(int id) {
-        final Notification.Builder b = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setContentTitle("Title")
-                .setContentText("Text");
-        return createSbn(id, b);
-    }
-
-    protected NotificationEntry createEntry(int id, Notification n) {
-        return new NotificationEntryBuilder().setSbn(createSbn(id, n)).build();
-    }
-
-    protected NotificationEntry createEntry(int id) {
-        return new NotificationEntryBuilder().setSbn(createSbn(id)).build();
-    }
-
-
     private BaseHeadsUpManager createHeadsUpManager() {
         return new TestableHeadsUpManager(mContext, mLogger, mExecutor, mGlobalSettings,
                 mSystemClock, mAccessibilityMgr, mUiEventLoggerFake);
@@ -257,7 +107,7 @@
                 .setSmallIcon(R.drawable.ic_person)
                 .setFullScreenIntent(mock(PendingIntent.class), /* highPriority */ true)
                 .build();
-        return createEntry(id, notif);
+        return HeadsUpManagerTestUtil.createEntry(id, notif);
     }
 
     private NotificationEntry createStickyForSomeTimeEntry(int id) {
@@ -265,7 +115,7 @@
                 .setSmallIcon(R.drawable.ic_person)
                 .setFlag(FLAG_FSI_REQUESTED_BUT_DENIED, true)
                 .build();
-        return createEntry(id, notif);
+        return HeadsUpManagerTestUtil.createEntry(id, notif);
     }
 
     private PendingIntent createFullScreenIntent() {
@@ -279,7 +129,7 @@
                 .setSmallIcon(R.drawable.ic_person)
                 .setFullScreenIntent(createFullScreenIntent(), /* highPriority */ true)
                 .build();
-        return createEntry(id, notif);
+        return HeadsUpManagerTestUtil.createEntry(id, notif);
     }
 
 
@@ -293,10 +143,16 @@
         }
     }
 
+    @Override
+    public void SysuiSetup() throws Exception {
+        super.SysuiSetup();
+        mSetFlagsRule.disableFlags(NotificationThrottleHun.FLAG_NAME);
+    }
+
     @Test
     public void testShowNotification_addsEntry() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
 
@@ -308,7 +164,7 @@
     @Test
     public void testShowNotification_autoDismisses() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
         mSystemClock.advanceTime(TEST_AUTO_DISMISS_TIME * 3 / 2);
@@ -319,7 +175,7 @@
     @Test
     public void testRemoveNotification_removeDeferred() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
 
@@ -332,7 +188,7 @@
     @Test
     public void testRemoveNotification_forceRemove() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
 
@@ -346,7 +202,7 @@
     public void testReleaseAllImmediately() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
         for (int i = 0; i < TEST_NUM_NOTIFICATIONS; i++) {
-            final NotificationEntry entry = createEntry(i);
+            final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(i, mContext);
             entry.setRow(mRow);
             alm.showNotification(entry);
         }
@@ -359,7 +215,7 @@
     @Test
     public void testCanRemoveImmediately_notShownLongEnough() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
 
@@ -370,7 +226,8 @@
     @Test
     public void testHunRemovedLogging() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+        final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+                mContext);
         final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = mock(
                 BaseHeadsUpManager.HeadsUpEntry.class);
         headsUpEntry.mEntry = notifEntry;
@@ -413,7 +270,7 @@
     @Test
     public void testShouldHeadsUpBecomePinned_noFSI_false() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         assertFalse(hum.shouldHeadsUpBecomePinned(entry));
     }
@@ -422,7 +279,7 @@
     @Test
     public void testShowNotification_autoDismissesIncludingTouchAcceptanceDelay() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(false);
 
         hum.showNotification(entry);
@@ -435,7 +292,7 @@
     @Test
     public void testShowNotification_autoDismissesWithDefaultTimeout() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(false);
 
         hum.showNotification(entry);
@@ -476,7 +333,7 @@
     @Test
     public void testShowNotification_autoDismissesWithAccessibilityTimeout() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(true);
 
         hum.showNotification(entry);
@@ -504,7 +361,7 @@
     @Test
     public void testRemoveNotification_beforeMinimumDisplayTime() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(false);
 
         hum.showNotification(entry);
@@ -523,7 +380,7 @@
     @Test
     public void testRemoveNotification_afterMinimumDisplayTime() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(false);
 
         hum.showNotification(entry);
@@ -541,7 +398,7 @@
     @Test
     public void testRemoveNotification_releaseImmediately() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         hum.showNotification(entry);
 
@@ -555,7 +412,8 @@
     @Test
     public void testIsSticky_rowPinnedAndExpanded_true() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+        final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+                mContext);
         when(mRow.isPinned()).thenReturn(true);
         notifEntry.setRow(mRow);
 
@@ -571,7 +429,8 @@
     @Test
     public void testIsSticky_remoteInputActive_true() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+        final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+                mContext);
 
         hum.showNotification(notifEntry);
 
@@ -607,7 +466,8 @@
     @Test
     public void testIsSticky_false() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+        final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+                mContext);
 
         hum.showNotification(notifEntry);
 
@@ -653,14 +513,14 @@
 
         final BaseHeadsUpManager.HeadsUpEntry ongoingCall = hum.new HeadsUpEntry();
         ongoingCall.setEntry(new NotificationEntryBuilder()
-                .setSbn(createSbn(/* id = */ 0,
+                .setSbn(HeadsUpManagerTestUtil.createSbn(/* id = */ 0,
                         new Notification.Builder(mContext, "")
                                 .setCategory(Notification.CATEGORY_CALL)
                                 .setOngoing(true)))
                 .build());
 
         final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
-        activeRemoteInput.setEntry(createEntry(/* id = */ 1));
+        activeRemoteInput.setEntry(HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext));
         activeRemoteInput.mRemoteInputActive = true;
 
         assertThat(ongoingCall.compareTo(activeRemoteInput)).isLessThan(0);
@@ -675,14 +535,14 @@
         final Person person = new Person.Builder().setName("person").build();
         final PendingIntent intent = mock(PendingIntent.class);
         incomingCall.setEntry(new NotificationEntryBuilder()
-                .setSbn(createSbn(/* id = */ 0,
+                .setSbn(HeadsUpManagerTestUtil.createSbn(/* id = */ 0,
                         new Notification.Builder(mContext, "")
                                 .setStyle(Notification.CallStyle
                                         .forIncomingCall(person, intent, intent))))
                 .build());
 
         final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
-        activeRemoteInput.setEntry(createEntry(/* id = */ 1));
+        activeRemoteInput.setEntry(HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext));
         activeRemoteInput.mRemoteInputActive = true;
 
         assertThat(incomingCall.compareTo(activeRemoteInput)).isLessThan(0);
@@ -712,7 +572,8 @@
     @Test
     public void testSetUserActionMayIndirectlyRemove() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+        final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+                mContext);
 
         hum.showNotification(notifEntry);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
similarity index 87%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
index c350de2..c032d7c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.phone;
+package com.android.systemui.statusbar.policy;
 
 import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer;
 import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
@@ -26,10 +26,10 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
 import androidx.test.filters.SmallTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -39,11 +39,10 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
-import com.android.systemui.statusbar.policy.BaseHeadsUpManagerTest;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
+import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
+import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.settings.GlobalSettings;
@@ -61,7 +60,7 @@
 import kotlinx.coroutines.flow.StateFlowKt;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class HeadsUpManagerPhoneTest extends BaseHeadsUpManagerTest {
     @Rule public MockitoRule rule = MockitoJUnit.rule();
@@ -138,6 +137,8 @@
 
     @Before
     public void setUp() {
+        mSetFlagsRule.disableFlags(NotificationThrottleHun.FLAG_NAME);
+
         when(mShadeInteractor.isAnyExpanded()).thenReturn(StateFlowKt.MutableStateFlow(false));
         final AccessibilityManagerWrapper accessibilityMgr =
                 mDependency.injectMockDependency(AccessibilityManagerWrapper.class);
@@ -152,7 +153,7 @@
     @Test
     public void testSnooze() {
         final HeadsUpManager hmp = createHeadsUpManagerPhone();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         hmp.showNotification(entry);
         hmp.snooze();
@@ -163,7 +164,7 @@
     @Test
     public void testSwipedOutNotification() {
         final HeadsUpManager hmp = createHeadsUpManagerPhone();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         hmp.showNotification(entry);
         hmp.addSwipedOutNotification(entry.getKey());
@@ -179,7 +180,7 @@
     @Test
     public void testCanRemoveImmediately_swipedOut() {
         final HeadsUpManager hmp = createHeadsUpManagerPhone();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         hmp.showNotification(entry);
         hmp.addSwipedOutNotification(entry.getKey());
@@ -192,8 +193,10 @@
     @Test
     public void testCanRemoveImmediately_notTopEntry() {
         final HeadsUpManager hmp = createHeadsUpManagerPhone();
-        final NotificationEntry earlierEntry = createEntry(/* id = */ 0);
-        final NotificationEntry laterEntry = createEntry(/* id = */ 1);
+        final NotificationEntry earlierEntry =
+                HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
+        final NotificationEntry laterEntry =
+                HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext);
         laterEntry.setRow(mRow);
 
         hmp.showNotification(earlierEntry);
@@ -206,7 +209,7 @@
     @Test
     public void testExtendHeadsUp() {
         final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         hmp.showNotification(entry);
         hmp.extendHeadsUp();
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java
new file mode 100644
index 0000000..c70b03b
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+import android.app.ActivityManager;
+import android.os.UserHandle;
+
+import android.content.Context;
+import android.service.notification.StatusBarNotification;
+import android.app.Notification;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+
+/**
+ * Test helper class for HeadsUpEntry creation.
+ */
+public class HeadsUpManagerTestUtil {
+
+    private static final String TEST_PACKAGE_NAME = "HeadsUpManagerTestUtil";
+    private static final int TEST_UID = 0;
+
+    protected static StatusBarNotification createSbn(int id, Notification.Builder n) {
+        return createSbn(id, n.build());
+    }
+
+    protected static StatusBarNotification createSbn(int id, Context context) {
+        final Notification.Builder b = new Notification.Builder(context, "")
+                .setSmallIcon(com.android.systemui.res.R.drawable.ic_person)
+                .setContentTitle("Title")
+                .setContentText("Text");
+        return createSbn(id, b);
+    }
+
+    protected static StatusBarNotification createSbn(int id, Notification n) {
+        return new StatusBarNotification(
+                TEST_PACKAGE_NAME /* pkg */,
+                TEST_PACKAGE_NAME,
+                id,
+                null /* tag */,
+                TEST_UID,
+                0 /* initialPid */,
+                n,
+                new UserHandle(ActivityManager.getCurrentUser()),
+                null /* overrideGroupKey */,
+                0 /* postTime */);
+    }
+
+    protected static NotificationEntry createEntry(int id, Notification n) {
+        return new NotificationEntryBuilder().setSbn(createSbn(id, n)).build();
+    }
+
+    protected static NotificationEntry createEntry(int id, Context context) {
+        return new NotificationEntryBuilder().setSbn(
+                HeadsUpManagerTestUtil.createSbn(id, context)).build();
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
new file mode 100644
index 0000000..2747629
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
+import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
+
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.graphics.Region;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.settings.GlobalSettings;
+import com.android.systemui.util.time.SystemClock;
+
+class TestableHeadsUpManager extends BaseHeadsUpManager {
+
+    private HeadsUpEntry mLastCreatedEntry;
+
+    TestableHeadsUpManager(Context context,
+            HeadsUpManagerLogger logger,
+            DelayableExecutor executor,
+            GlobalSettings globalSettings,
+            SystemClock systemClock,
+            AccessibilityManagerWrapper accessibilityManagerWrapper,
+            UiEventLogger uiEventLogger) {
+        super(context, logger, mockExecutorHandler(executor), globalSettings, systemClock,
+                executor, accessibilityManagerWrapper, uiEventLogger);
+
+        mTouchAcceptanceDelay = BaseHeadsUpManagerTest.TEST_TOUCH_ACCEPTANCE_TIME;
+        mMinimumDisplayTime = BaseHeadsUpManagerTest.TEST_MINIMUM_DISPLAY_TIME;
+        mAutoDismissTime = BaseHeadsUpManagerTest.TEST_AUTO_DISMISS_TIME;
+        mStickyForSomeTimeAutoDismissTime = BaseHeadsUpManagerTest.TEST_STICKY_AUTO_DISMISS_TIME;
+    }
+
+    @Override
+    protected HeadsUpEntry createHeadsUpEntry() {
+        mLastCreatedEntry = spy(super.createHeadsUpEntry());
+        return mLastCreatedEntry;
+    }
+
+    @Override
+    public int getContentFlag() {
+        return FLAG_CONTENT_VIEW_CONTRACTED;
+    }
+
+    // The following are only implemented by HeadsUpManagerPhone. If you need them, use that.
+    @Override
+    public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addSwipedOutNotification(@NonNull String key) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void extendHeadsUp() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Nullable
+    @Override
+    public Region getTouchableRegion() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isHeadsUpGoingAway() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void onExpandingFinished() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean removeNotification(@NonNull String key, boolean releaseImmediately,
+            boolean animate) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setAnimationStateHandler(@NonNull AnimationStateHandler handler) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setRemoteInputActive(@NonNull NotificationEntry entry,
+            boolean remoteInputActive) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setTrackingHeadsUp(boolean tracking) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean shouldSwallowClick(@NonNull String key) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/ClientTrackingWakeLockTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/ClientTrackingWakeLockTest.kt
new file mode 100644
index 0000000..fdfcdc4
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/ClientTrackingWakeLockTest.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.wakelock
+
+import android.os.Build
+import android.os.PowerManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.After
+import org.junit.Assert
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ClientTrackingWakeLockTest : SysuiTestCase() {
+
+    private val WHY = "test"
+    private val WHY_2 = "test2"
+
+    lateinit var mWakeLock: ClientTrackingWakeLock
+    lateinit var mInner: PowerManager.WakeLock
+
+    @Before
+    fun setUp() {
+        mInner =
+            WakeLock.createWakeLockInner(mContext, "WakeLockTest", PowerManager.PARTIAL_WAKE_LOCK)
+        mWakeLock = ClientTrackingWakeLock(mInner, null, 20000)
+    }
+
+    @After
+    fun tearDown() {
+        mInner.setReferenceCounted(false)
+        mInner.release()
+    }
+
+    @Test
+    fun createPartialInner_notHeldYet() {
+        Assert.assertFalse(mInner.isHeld)
+    }
+
+    @Test
+    fun wakeLock_acquire() {
+        mWakeLock.acquire(WHY)
+        Assert.assertTrue(mInner.isHeld)
+    }
+
+    @Test
+    fun wakeLock_release() {
+        mWakeLock.acquire(WHY)
+        mWakeLock.release(WHY)
+        Assert.assertFalse(mInner.isHeld)
+    }
+
+    @Test
+    fun wakeLock_acquiredReleasedMultipleSources_stillHeld() {
+        mWakeLock.acquire(WHY)
+        mWakeLock.acquire(WHY_2)
+        mWakeLock.release(WHY)
+
+        Assert.assertTrue(mInner.isHeld)
+        mWakeLock.release(WHY_2)
+        Assert.assertFalse(mInner.isHeld)
+    }
+
+    @Test
+    fun wakeLock_releasedTooManyTimes_stillReleased_noThrow() {
+        Assume.assumeFalse(Build.IS_ENG)
+        mWakeLock.acquire(WHY)
+        mWakeLock.acquire(WHY_2)
+        mWakeLock.release(WHY)
+        mWakeLock.release(WHY_2)
+        mWakeLock.release(WHY)
+        Assert.assertFalse(mInner.isHeld)
+    }
+
+    @Test
+    fun wakeLock_wrap() {
+        val ran = BooleanArray(1)
+        val wrapped = mWakeLock.wrap { ran[0] = true }
+        Assert.assertTrue(mInner.isHeld)
+        Assert.assertFalse(ran[0])
+        wrapped.run()
+        Assert.assertTrue(ran[0])
+        Assert.assertFalse(mInner.isHeld)
+    }
+
+    @Test
+    fun prodBuild_wakeLock_releaseWithoutAcquire_noThrow() {
+        Assume.assumeFalse(Build.IS_ENG)
+        // shouldn't throw an exception on production builds
+        mWakeLock.release(WHY)
+    }
+
+    @Test
+    fun acquireSeveralLocks_stringReportsCorrectCount() {
+        mWakeLock.acquire(WHY)
+        mWakeLock.acquire(WHY_2)
+        mWakeLock.acquire(WHY)
+        mWakeLock.acquire(WHY)
+        mWakeLock.acquire(WHY_2)
+        Assert.assertEquals(5, mWakeLock.activeClients())
+
+        mWakeLock.release(WHY_2)
+        mWakeLock.release(WHY_2)
+        Assert.assertEquals(3, mWakeLock.activeClients())
+
+        mWakeLock.release(WHY)
+        mWakeLock.release(WHY)
+        mWakeLock.release(WHY)
+        Assert.assertEquals(0, mWakeLock.activeClients())
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt
new file mode 100644
index 0000000..737b7f3
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.spatial
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.media.spatializerInteractor
+import com.android.systemui.volume.mediaOutputInteractor
+import com.android.systemui.volume.panel.component.spatial.domain.interactor.SpatialAudioComponentInteractor
+
+val Kosmos.spatialAudioComponentInteractor by
+    Kosmos.Fixture {
+        SpatialAudioComponentInteractor(
+            mediaOutputInteractor,
+            spatializerInteractor,
+            testScope.backgroundScope
+        )
+    }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteriaTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteriaTest.kt
new file mode 100644
index 0000000..36be90e
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteriaTest.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.spatial.domain
+
+import android.media.session.MediaSession
+import android.media.session.PlaybackState
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.media.BluetoothMediaDevice
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.media.spatializerRepository
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.volume.localMediaRepository
+import com.android.systemui.volume.mediaController
+import com.android.systemui.volume.mediaControllerRepository
+import com.android.systemui.volume.panel.component.spatial.spatialAudioComponentInteractor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@RunWithLooper(setAsMainLooper = true)
+class SpatialAudioAvailabilityCriteriaTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+    private val cachedBluetoothDevice: CachedBluetoothDevice = mock {
+        whenever(address).thenReturn("test_address")
+    }
+    private val bluetoothMediaDevice: BluetoothMediaDevice = mock {
+        whenever(cachedDevice).thenReturn(cachedBluetoothDevice)
+    }
+
+    private lateinit var underTest: SpatialAudioAvailabilityCriteria
+
+    @Before
+    fun setup() {
+        with(kosmos) {
+            mediaControllerRepository.setActiveLocalMediaController(
+                mediaController.apply {
+                    whenever(packageName).thenReturn("test.pkg")
+                    whenever(sessionToken).thenReturn(MediaSession.Token(0, mock {}))
+                    whenever(playbackState).thenReturn(PlaybackState.Builder().build())
+                }
+            )
+
+            underTest = SpatialAudioAvailabilityCriteria(spatialAudioComponentInteractor)
+        }
+    }
+
+    @Test
+    fun noSpatialAudio_noHeadTracking_unavailable() {
+        with(kosmos) {
+            testScope.runTest {
+                localMediaRepository.updateCurrentConnectedDevice(bluetoothMediaDevice)
+                spatializerRepository.setIsHeadTrackingAvailable(false)
+                spatializerRepository.defaultSpatialAudioAvailable = false
+
+                val isAvailable by collectLastValue(underTest.isAvailable())
+                runCurrent()
+
+                assertThat(isAvailable).isFalse()
+            }
+        }
+    }
+
+    @Test
+    fun spatialAudio_noHeadTracking_available() {
+        with(kosmos) {
+            testScope.runTest {
+                localMediaRepository.updateCurrentConnectedDevice(bluetoothMediaDevice)
+                spatializerRepository.setIsHeadTrackingAvailable(false)
+                spatializerRepository.defaultSpatialAudioAvailable = true
+
+                val isAvailable by collectLastValue(underTest.isAvailable())
+                runCurrent()
+
+                assertThat(isAvailable).isTrue()
+            }
+        }
+    }
+
+    @Test
+    fun spatialAudio_headTracking_available() {
+        with(kosmos) {
+            testScope.runTest {
+                localMediaRepository.updateCurrentConnectedDevice(bluetoothMediaDevice)
+                spatializerRepository.setIsHeadTrackingAvailable(true)
+                spatializerRepository.defaultSpatialAudioAvailable = true
+
+                val isAvailable by collectLastValue(underTest.isAvailable())
+                runCurrent()
+
+                assertThat(isAvailable).isTrue()
+            }
+        }
+    }
+
+    @Test
+    fun spatialAudio_headTracking_noDevice_unavailable() {
+        with(kosmos) {
+            testScope.runTest {
+                spatializerRepository.setIsHeadTrackingAvailable(true)
+                spatializerRepository.defaultSpatialAudioAvailable = true
+
+                val isAvailable by collectLastValue(underTest.isAvailable())
+                runCurrent()
+
+                assertThat(isAvailable).isFalse()
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt
new file mode 100644
index 0000000..eb6f0b2
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.spatial.domain.interactor
+
+import android.media.AudioDeviceAttributes
+import android.media.AudioDeviceInfo
+import android.media.session.MediaSession
+import android.media.session.PlaybackState
+import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.media.BluetoothMediaDevice
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.media.spatializerInteractor
+import com.android.systemui.media.spatializerRepository
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.volume.localMediaRepository
+import com.android.systemui.volume.mediaController
+import com.android.systemui.volume.mediaControllerRepository
+import com.android.systemui.volume.mediaOutputInteractor
+import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioEnabledModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class SpatialAudioComponentInteractorTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+    private lateinit var underTest: SpatialAudioComponentInteractor
+
+    @Before
+    fun setup() {
+        with(kosmos) {
+            val cachedBluetoothDevice: CachedBluetoothDevice = mock {
+                whenever(address).thenReturn("test_address")
+            }
+            localMediaRepository.updateCurrentConnectedDevice(
+                mock<BluetoothMediaDevice> {
+                    whenever(name).thenReturn("test_device")
+                    whenever(cachedDevice).thenReturn(cachedBluetoothDevice)
+                }
+            )
+
+            whenever(mediaController.packageName).thenReturn("test.pkg")
+            whenever(mediaController.sessionToken).thenReturn(MediaSession.Token(0, mock {}))
+            whenever(mediaController.playbackState).thenReturn(PlaybackState.Builder().build())
+
+            mediaControllerRepository.setActiveLocalMediaController(mediaController)
+
+            spatializerRepository.setIsSpatialAudioAvailable(
+                AudioDeviceAttributes(
+                    AudioDeviceAttributes.ROLE_OUTPUT,
+                    AudioDeviceInfo.TYPE_BLE_HEADSET,
+                    "test_address"
+                ),
+                true
+            )
+            spatializerRepository.setIsHeadTrackingAvailable(true)
+
+            underTest =
+                SpatialAudioComponentInteractor(
+                    mediaOutputInteractor,
+                    spatializerInteractor,
+                    testScope.backgroundScope,
+                )
+        }
+    }
+
+    @Test
+    fun setEnabled_changesIsEnabled() {
+        with(kosmos) {
+            testScope.runTest {
+                val values by collectValues(underTest.isEnabled)
+
+                underTest.setEnabled(SpatialAudioEnabledModel.Disabled)
+                runCurrent()
+                underTest.setEnabled(SpatialAudioEnabledModel.HeadTrackingEnabled)
+                runCurrent()
+                underTest.setEnabled(SpatialAudioEnabledModel.SpatialAudioEnabled)
+                runCurrent()
+
+                assertThat(values)
+                    .containsExactly(
+                        SpatialAudioEnabledModel.Disabled,
+                        SpatialAudioEnabledModel.HeadTrackingEnabled,
+                        SpatialAudioEnabledModel.SpatialAudioEnabled,
+                    )
+                    .inOrder()
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/res/drawable/battery_unified_attr_charging.xml b/packages/SystemUI/res/drawable/battery_unified_attr_charging.xml
new file mode 100644
index 0000000..8e3b89b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/battery_unified_attr_charging.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="8dp"
+    android:height="10dp"
+    android:viewportWidth="16.0"
+    android:viewportHeight="20.0">
+    <path
+        android:pathData="M4,20L5,13H0L9,0H11L10,8H16L6,20H4Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/battery_unified_attr_defend.xml b/packages/SystemUI/res/drawable/battery_unified_attr_defend.xml
new file mode 100644
index 0000000..e7beee2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/battery_unified_attr_defend.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="8dp"
+    android:height="9dp"
+    android:viewportWidth="8.0"
+    android:viewportHeight="9.0">
+    <path
+        android:pathData="M3.698,9C2.629,8.765 1.746,8.181 1.048,7.247C0.349,6.306 0,5.266 0,4.126V1.422L3.698,0L7.397,1.422V4.126C7.397,5.266 7.048,6.306 6.349,7.247C5.651,8.181 4.767,8.765 3.698,9ZM3.698,7.846C4.439,7.596 5.052,7.129 5.537,6.445C6.029,5.754 6.274,4.981 6.274,4.126V2.191L3.698,1.197L1.122,2.191V4.126C1.122,4.981 1.365,5.754 1.849,6.445C2.341,7.129 2.957,7.596 3.698,7.846ZM3.698,7.183C3.1,6.99 2.605,6.616 2.213,6.061C1.828,5.505 1.635,4.888 1.635,4.211V2.651L3.698,1.86L5.761,2.651V4.211C5.761,4.888 5.565,5.505 5.173,6.061C4.789,6.616 4.297,6.99 3.698,7.183Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/battery_unified_attr_powersave.xml b/packages/SystemUI/res/drawable/battery_unified_attr_powersave.xml
new file mode 100644
index 0000000..a2c0cbae
--- /dev/null
+++ b/packages/SystemUI/res/drawable/battery_unified_attr_powersave.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- This drawable is inset for now until the unified battery attrs can get their own paddings -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetRight="0.5dp"
+    >
+    <vector
+        android:width="8dp"
+        android:height="8dp"
+        android:viewportWidth="8.0"
+        android:viewportHeight="8.0"
+        >
+        <path
+            android:pathData="M3.242,4.758H0V3.257H3.242V0H4.758V3.257H8V4.758H4.758V8.015H3.242V4.758Z"
+            android:fillColor="#000"/>
+    </vector>
+</inset>
diff --git a/packages/SystemUI/res/drawable/battery_unified_frame.xml b/packages/SystemUI/res/drawable/battery_unified_frame.xml
new file mode 100644
index 0000000..016b88b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/battery_unified_frame.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- Unified battery frame for BatteryLayersDrawable.kt -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="14dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="14.0">
+    <!-- body -->
+    <path
+        android:pathData="@string/battery_unified_frame_path_string"
+        android:strokeColor="#000"
+        android:strokeWidth="1.5"
+        />
+    <!-- cap -->
+    <path
+        android:pathData="M0,4C0,3.448 0.448,3 1,3H1.5V11H1C0.448,11 0,10.552 0,10V4Z"
+        android:fillColor="#000"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/battery_unified_frame_bg.xml b/packages/SystemUI/res/drawable/battery_unified_frame_bg.xml
new file mode 100644
index 0000000..8e04f10
--- /dev/null
+++ b/packages/SystemUI/res/drawable/battery_unified_frame_bg.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- Vector description of the battery gutter: the background of the fill -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="14dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="14.0">
+    <path
+        android:pathData="@string/battery_unified_frame_path_string"
+        android:fillColor="#fff" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/bg_shutdown_finder_message.xml b/packages/SystemUI/res/drawable/bg_shutdown_finder_message.xml
new file mode 100644
index 0000000..324ae0c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/bg_shutdown_finder_message.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners android:radius="28dp" />
+    <solid android:color="@color/global_actions_lite_button_background" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_finder_active.xml b/packages/SystemUI/res/drawable/ic_finder_active.xml
new file mode 100644
index 0000000..8ca221a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_finder_active.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,0L12,0A12,12 0,0 1,24 12L24,12A12,12 0,0 1,12 24L12,24A12,12 0,0 1,0 12L0,12A12,12 0,0 1,12 0z"
+      android:fillColor="#00677D"/>
+  <path
+      android:pathData="M12.797,4.005C11.949,3.936 11.203,4.597 11.203,5.467V6.659C8.855,7.001 6.998,8.856 6.653,11.203H5.467C4.597,11.203 3.936,11.948 4.005,12.796L4.006,12.802L4.006,12.809C4.38,16.605 7.399,19.625 11.195,20C12.051,20.087 12.803,19.404 12.803,18.547V17.355C15.154,17.012 17.013,15.154 17.355,12.803H18.54C19.406,12.803 20.079,12.058 19.992,11.196C19.618,7.4 16.606,4.388 12.812,4.006L12.804,4.006L12.797,4.005ZM11.203,9.344V8.283C9.741,8.591 8.588,9.741 8.278,11.203H9.344C9.585,10.4 10.179,9.754 10.942,9.437C11.027,9.402 11.114,9.371 11.203,9.344ZM11.998,13.171C11.358,13.175 10.828,12.651 10.827,12.004H10.827C10.827,11.959 10.83,11.915 10.835,11.871C10.885,11.427 11.185,11.056 11.59,10.902C11.694,10.863 11.806,10.838 11.921,10.83C11.948,10.833 11.976,10.834 12.003,10.834C12.65,10.834 13.177,11.356 13.179,12.007C13.177,12.622 12.695,13.13 12.091,13.175C12.06,13.172 12.029,13.17 11.998,13.171ZM17.353,11.203H18.383C18.028,8.289 15.72,5.979 12.804,5.616V6.658C15.153,7 17.004,8.852 17.353,11.203ZM14.663,11.203C14.395,10.311 13.692,9.611 12.804,9.344V8.283C14.265,8.59 15.414,9.736 15.727,11.203H14.663ZM5.615,12.803H6.654C7.001,15.15 8.855,17.002 11.203,17.346V18.391C8.287,18.034 5.972,15.719 5.615,12.803ZM11.203,14.666C10.316,14.394 9.613,13.692 9.345,12.803H8.279C8.591,14.264 9.741,15.412 11.203,15.721V14.666ZM14.661,12.811H15.729C15.418,14.272 14.266,15.422 12.804,15.73V14.662C13.689,14.396 14.391,13.699 14.661,12.811Z"
+      android:fillColor="#ffffff"
+      android:fillType="evenOdd"/>
+</vector>
diff --git a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
new file mode 100644
index 0000000..5fe74aa
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
@@ -0,0 +1,322 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+xmlns:app="http://schemas.android.com/apk/res-auto"
+xmlns:tools="http://schemas.android.com/tools"
+android:layout_width="match_parent"
+android:layout_height="match_parent">
+
+    <ImageView
+        android:id="@+id/background"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:contentDescription="@string/biometric_dialog_empty_space_description"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <View
+        android:id="@+id/panel"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:background="?android:attr/colorBackgroundFloating"
+        android:clickable="true"
+        android:clipToOutline="true"
+        android:importantForAccessibility="no"
+        android:paddingHorizontal="16dp"
+        android:paddingVertical="16dp"
+        android:visibility="visible"
+        app:layout_constraintBottom_toTopOf="@+id/bottomGuideline"
+        app:layout_constraintEnd_toStartOf="@+id/rightGuideline"
+        app:layout_constraintStart_toStartOf="@+id/leftGuideline"
+        app:layout_constraintTop_toTopOf="@+id/topGuideline" />
+
+    <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
+        android:id="@+id/biometric_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.8"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:srcCompat="@tools:sample/avatars" />
+
+    <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
+        android:id="@+id/biometric_icon_overlay"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:layout_gravity="center"
+        android:contentDescription="@null"
+        android:scaleType="fitXY"
+        app:layout_constraintBottom_toBottomOf="@+id/biometric_icon"
+        app:layout_constraintEnd_toEndOf="@+id/biometric_icon"
+        app:layout_constraintStart_toStartOf="@+id/biometric_icon"
+        app:layout_constraintTop_toTopOf="@+id/biometric_icon" />
+
+    <ScrollView
+        android:id="@+id/scrollView"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:fillViewport="true"
+        android:padding="16dp"
+        app:layout_constrainedHeight="true"
+        app:layout_constrainedWidth="true"
+        app:layout_constraintBottom_toTopOf="@+id/buttonBarrier"
+        app:layout_constraintEnd_toStartOf="@+id/midGuideline"
+        app:layout_constraintStart_toStartOf="@id/leftGuideline"
+        app:layout_constraintTop_toTopOf="@+id/topGuideline">
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/innerConstraint"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <ImageView
+                android:id="@+id/logo"
+                android:layout_width="@dimen/biometric_auth_icon_size"
+                android:layout_height="@dimen/biometric_auth_icon_size"
+                android:layout_gravity="center"
+                android:scaleType="fitXY"
+                android:visibility="visible"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toTopOf="parent" />
+
+            <LinearLayout
+                android:id="@+id/customized_view_container"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="center_vertical"
+                android:orientation="vertical"
+                android:paddingHorizontal="0dp"
+                android:visibility="gone"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintHorizontal_bias="0.0"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/subtitle"
+                app:layout_constraintVertical_bias="0.0" />
+
+            <Space
+                android:id="@+id/space_above_content"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/biometric_prompt_space_above_content"
+                android:visibility="gone" />
+
+            <TextView
+                android:id="@+id/title"
+                style="@style/TextAppearance.AuthCredential.Title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="@integer/biometric_dialog_text_gravity"
+                android:paddingHorizontal="0dp"
+                android:textAlignment="viewStart"
+                app:layout_constraintBottom_toTopOf="@+id/subtitle"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintHorizontal_bias="0.0"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/logo"
+                app:layout_constraintVertical_bias="0.0"
+                app:layout_constraintVertical_chainStyle="packed" />
+
+            <TextView
+                android:id="@+id/subtitle"
+                style="@style/TextAppearance.AuthCredential.Subtitle"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="@integer/biometric_dialog_text_gravity"
+                android:paddingHorizontal="0dp"
+                android:textAlignment="viewStart"
+                app:layout_constraintBottom_toTopOf="@+id/contentBarrier"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintHorizontal_bias="0.0"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/title" />
+
+            <TextView
+                android:id="@+id/description"
+                style="@style/TextAppearance.AuthCredential.Description"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="@integer/biometric_dialog_text_gravity"
+                android:paddingHorizontal="0dp"
+                android:textAlignment="viewStart"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintHorizontal_bias="0.0"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/subtitle"
+                app:layout_constraintVertical_bias="0.0" />
+
+            <TextView
+                android:id="@+id/logo_description"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:ellipsize="marquee"
+                android:gravity="@integer/biometric_dialog_text_gravity"
+                android:marqueeRepeatLimit="1"
+                android:singleLine="true"
+                android:textAlignment="viewStart"
+                android:paddingLeft="8dp"
+                app:layout_constraintBottom_toBottomOf="@+id/logo"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toEndOf="@+id/logo"
+                app:layout_constraintTop_toTopOf="@+id/logo" />
+
+            <androidx.constraintlayout.widget.Barrier
+                android:id="@+id/contentBarrier"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                app:barrierAllowsGoneWidgets="false"
+                app:barrierDirection="top"
+                app:constraint_referenced_ids="description, customized_view_container" />
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+    </ScrollView>
+
+    <TextView
+        android:id="@+id/indicator"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:accessibilityLiveRegion="polite"
+        android:fadingEdge="horizontal"
+        android:gravity="center_horizontal"
+        android:marqueeRepeatLimit="marquee_forever"
+        android:scrollHorizontally="true"
+        android:textColor="@color/biometric_dialog_gray"
+        android:textSize="12sp"
+        app:layout_constraintBottom_toTopOf="@+id/buttonBarrier"
+        app:layout_constraintEnd_toEndOf="@+id/biometric_icon"
+        app:layout_constraintStart_toStartOf="@+id/biometric_icon"
+        app:layout_constraintTop_toBottomOf="@+id/biometric_icon"
+        app:layout_constraintVertical_bias="0.0" />
+
+    <!-- Negative Button, reserved for app -->
+    <Button
+        android:id="@+id/button_negative"
+        style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_marginBottom="8dp"
+        android:layout_marginLeft="8dp"
+        android:ellipsize="end"
+        android:maxLines="2"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toBottomOf="@+id/bottomGuideline"
+        app:layout_constraintStart_toStartOf="@+id/scrollView" />
+
+    <!-- Cancel Button, replaces negative button when biometric is accepted -->
+    <Button
+        android:id="@+id/button_cancel"
+        style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_marginBottom="8dp"
+        android:layout_marginLeft="8dp"
+        android:text="@string/cancel"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toBottomOf="@+id/bottomGuideline"
+        app:layout_constraintStart_toStartOf="@+id/scrollView" />
+
+    <!-- "Use Credential" Button, replaces if device credential is allowed -->
+    <Button
+        android:id="@+id/button_use_credential"
+        style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_marginBottom="8dp"
+        android:layout_marginLeft="8dp"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toBottomOf="@+id/bottomGuideline"
+        app:layout_constraintStart_toStartOf="@+id/scrollView" />
+
+    <!-- Positive Button -->
+    <Button
+        android:id="@+id/button_confirm"
+        style="@*android:style/Widget.DeviceDefault.Button.Colored"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_marginBottom="8dp"
+        android:layout_marginRight="8dp"
+        android:ellipsize="end"
+        android:maxLines="2"
+        android:text="@string/biometric_dialog_confirm"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toBottomOf="@+id/bottomGuideline"
+        app:layout_constraintEnd_toEndOf="@+id/scrollView"
+        tools:visibility="invisible" />
+
+    <!-- Try Again Button -->
+    <Button
+        android:id="@+id/button_try_again"
+        style="@*android:style/Widget.DeviceDefault.Button.Colored"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_marginBottom="8dp"
+        android:layout_marginRight="8dp"
+        android:ellipsize="end"
+        android:maxLines="2"
+        android:text="@string/biometric_dialog_try_again"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toBottomOf="@+id/bottomGuideline"
+        app:layout_constraintEnd_toEndOf="@+id/scrollView" />
+
+    <!-- Guidelines for setting panel border -->
+    <androidx.constraintlayout.widget.Barrier
+        android:id="@+id/topBarrier"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:barrierAllowsGoneWidgets="false"
+        app:barrierDirection="top"
+        app:constraint_referenced_ids="scrollView" />
+
+    <androidx.constraintlayout.widget.Barrier
+        android:id="@+id/buttonBarrier"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:barrierAllowsGoneWidgets="false"
+        app:barrierDirection="top"
+        app:constraint_referenced_ids="button_negative, button_cancel, button_use_credential, button_confirm, button_try_again" />
+
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/leftGuideline"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        app:layout_constraintGuide_begin="@dimen/biometric_dialog_border_padding" />
+
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/rightGuideline"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        app:layout_constraintGuide_end="@dimen/biometric_dialog_border_padding" />
+
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/midGuideline"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        app:layout_constraintGuide_begin="406dp" />
+
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/bottomGuideline"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        app:layout_constraintGuide_end="@dimen/biometric_dialog_border_padding" />
+
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/topGuideline"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:orientation="horizontal"
+        app:layout_constraintGuide_begin="@dimen/biometric_dialog_border_padding" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
new file mode 100644
index 0000000..5b30dfb
--- /dev/null
+++ b/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <ImageView
+        android:id="@+id/background"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:contentDescription="@string/biometric_dialog_empty_space_description"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <View
+        android:id="@+id/panel"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:background="?android:attr/colorBackgroundFloating"
+        android:clickable="true"
+        android:clipToOutline="true"
+        android:importantForAccessibility="no"
+        android:paddingHorizontal="16dp"
+        android:paddingVertical="16dp"
+        android:visibility="visible"
+        app:layout_constraintBottom_toTopOf="@+id/bottomGuideline"
+        app:layout_constraintEnd_toStartOf="@+id/rightGuideline"
+        app:layout_constraintStart_toStartOf="@+id/leftGuideline"
+        app:layout_constraintTop_toTopOf="@+id/topBarrier" />
+
+    <Button
+        android:id="@+id/button_negative"
+        style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_marginBottom="8dp"
+        android:layout_marginLeft="8dp"
+        android:ellipsize="end"
+        android:maxLines="2"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toBottomOf="@+id/panel"
+        app:layout_constraintStart_toStartOf="@+id/panel" />
+
+    <Button
+        android:id="@+id/button_cancel"
+        style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_marginBottom="8dp"
+        android:layout_marginLeft="8dp"
+        android:text="@string/cancel"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toBottomOf="@+id/panel"
+        app:layout_constraintStart_toStartOf="@+id/panel" />
+
+    <Button
+        android:id="@+id/button_use_credential"
+        style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_marginBottom="8dp"
+        android:layout_marginLeft="8dp"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toBottomOf="@+id/panel"
+        app:layout_constraintStart_toStartOf="@+id/panel" />
+
+    <Button
+        android:id="@+id/button_confirm"
+        style="@*android:style/Widget.DeviceDefault.Button.Colored"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_marginBottom="8dp"
+        android:layout_marginRight="8dp"
+        android:ellipsize="end"
+        android:maxLines="2"
+        android:text="@string/biometric_dialog_confirm"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toBottomOf="@+id/panel"
+        app:layout_constraintEnd_toEndOf="@+id/panel"
+        tools:visibility="invisible" />
+
+    <Button
+        android:id="@+id/button_try_again"
+        style="@*android:style/Widget.DeviceDefault.Button.Colored"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_marginBottom="8dp"
+        android:layout_marginRight="8dp"
+        android:ellipsize="end"
+        android:maxLines="2"
+        android:text="@string/biometric_dialog_try_again"
+        android:visibility="invisible"
+        app:layout_constraintBottom_toBottomOf="@+id/panel"
+        app:layout_constraintEnd_toEndOf="@+id/panel" />
+
+    <!-- Negative Button, reserved for app -->
+
+    <ScrollView
+        android:id="@+id/scrollView"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:fillViewport="true"
+        android:padding="16dp"
+        app:layout_constrainedHeight="true"
+        app:layout_constrainedWidth="true"
+        app:layout_constraintBottom_toTopOf="@+id/biometric_icon"
+        app:layout_constraintEnd_toEndOf="@id/panel"
+        app:layout_constraintStart_toStartOf="@id/panel"
+        app:layout_constraintTop_toTopOf="@+id/topGuideline"
+        app:layout_constraintVertical_bias="1.0">
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/innerConstraint"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <ImageView
+                android:id="@+id/logo"
+                android:layout_width="@dimen/biometric_auth_icon_size"
+                android:layout_height="@dimen/biometric_auth_icon_size"
+                android:layout_gravity="center"
+                android:scaleType="fitXY"
+                android:visibility="visible"
+                app:layout_constraintBottom_toTopOf="@+id/logo_description"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toTopOf="parent" />
+
+            <LinearLayout
+                android:id="@+id/customized_view_container"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="center_vertical"
+                android:orientation="vertical"
+                android:paddingHorizontal="@dimen/biometric_prompt_content_container_padding_horizontal"
+                android:visibility="gone"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/subtitle" />
+
+            <Space
+                android:id="@+id/space_above_content"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/biometric_prompt_space_above_content"
+                android:visibility="gone" />
+
+            <TextView
+                android:id="@+id/title"
+                style="@style/TextAppearance.AuthCredential.Title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="@integer/biometric_dialog_text_gravity"
+                app:layout_constraintBottom_toTopOf="@+id/subtitle"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/logo_description" />
+
+            <TextView
+                android:id="@+id/subtitle"
+                style="@style/TextAppearance.AuthCredential.Subtitle"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="@integer/biometric_dialog_text_gravity"
+                app:layout_constraintBottom_toTopOf="@+id/contentBarrier"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/title" />
+
+            <TextView
+                android:id="@+id/logo_description"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:ellipsize="marquee"
+                android:gravity="@integer/biometric_dialog_text_gravity"
+                android:marqueeRepeatLimit="1"
+                android:singleLine="true"
+                app:layout_constraintBottom_toTopOf="@+id/title"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/logo" />
+
+            <TextView
+                android:id="@+id/description"
+                style="@style/TextAppearance.AuthCredential.Description"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="@integer/biometric_dialog_text_gravity"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/subtitle" />
+
+            <androidx.constraintlayout.widget.Barrier
+                android:id="@+id/contentBarrier"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                app:barrierAllowsGoneWidgets="false"
+                app:barrierDirection="top"
+                app:constraint_referenced_ids="description, customized_view_container" />
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+    </ScrollView>
+
+    <!-- Cancel Button, replaces negative button when biometric is accepted -->
+    <TextView
+        android:id="@+id/indicator"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:accessibilityLiveRegion="polite"
+        android:fadingEdge="horizontal"
+        android:gravity="center_horizontal"
+        android:marqueeRepeatLimit="marquee_forever"
+        android:scrollHorizontally="true"
+        android:textColor="@color/biometric_dialog_gray"
+        android:textSize="12sp"
+        app:layout_constraintBottom_toTopOf="@+id/buttonBarrier"
+        app:layout_constraintEnd_toEndOf="@+id/panel"
+        app:layout_constraintStart_toStartOf="@+id/panel"
+        app:layout_constraintTop_toBottomOf="@+id/biometric_icon"
+        app:layout_constraintVertical_bias="0.0" />
+
+    <!-- "Use Credential" Button, replaces if device credential is allowed -->
+
+    <!-- Positive Button -->
+    <androidx.constraintlayout.widget.Barrier
+        android:id="@+id/topBarrier"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:barrierAllowsGoneWidgets="false"
+        app:barrierDirection="top"
+        app:constraint_referenced_ids="scrollView" />
+
+    <!-- Try Again Button -->
+    <androidx.constraintlayout.widget.Barrier
+        android:id="@+id/buttonBarrier"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:barrierAllowsGoneWidgets="false"
+        app:barrierDirection="top"
+        app:constraint_referenced_ids="button_negative, button_cancel, button_use_credential, button_confirm, button_try_again" />
+
+    <!-- Guidelines for setting panel border -->
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/leftGuideline"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        app:layout_constraintGuide_begin="@dimen/biometric_dialog_border_padding" />
+
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/rightGuideline"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        app:layout_constraintGuide_end="@dimen/biometric_dialog_border_padding" />
+
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/bottomGuideline"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        app:layout_constraintGuide_end="@dimen/biometric_dialog_border_padding" />
+
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/topGuideline"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:orientation="horizontal"
+        app:layout_constraintGuide_percent="0.25171" />
+
+    <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
+        android:id="@+id/biometric_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_bias="0.8"
+        tools:srcCompat="@tools:sample/avatars" />
+
+    <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
+        android:id="@+id/biometric_icon_overlay"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:layout_gravity="center"
+        android:contentDescription="@null"
+        android:scaleType="fitXY"
+        app:layout_constraintBottom_toBottomOf="@+id/biometric_icon"
+        app:layout_constraintEnd_toEndOf="@+id/biometric_icon"
+        app:layout_constraintStart_toStartOf="@+id/biometric_icon"
+        app:layout_constraintTop_toTopOf="@+id/biometric_icon" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
index 0ecdcfc..74292b4 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
@@ -1,27 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-xmlns:app="http://schemas.android.com/apk/res-auto"
-xmlns:tools="http://schemas.android.com/tools"
-android:layout_width="match_parent"
-android:layout_height="match_parent">
-
-    <ImageView
-        android:id="@+id/logo"
-        android:layout_width="@dimen/biometric_auth_icon_size"
-        android:layout_height="@dimen/biometric_auth_icon_size"
-        android:layout_gravity="center"
-        android:scaleType="fitXY"
-        android:visibility="gone" />
-
-    <TextView
-        android:id="@+id/logo_description"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="@integer/biometric_dialog_text_gravity"
-        android:singleLine="true"
-        android:marqueeRepeatLimit="1"
-        android:ellipsize="marquee"
-        android:visibility="gone"/>
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
 
     <ImageView
         android:id="@+id/background"
@@ -47,7 +29,7 @@
         app:layout_constraintBottom_toTopOf="@+id/bottomGuideline"
         app:layout_constraintEnd_toStartOf="@+id/rightGuideline"
         app:layout_constraintStart_toStartOf="@+id/leftGuideline"
-        app:layout_constraintTop_toTopOf="@+id/title" />
+        app:layout_constraintTop_toTopOf="@+id/topBarrier" />
 
     <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
         android:id="@+id/biometric_icon"
@@ -69,90 +51,133 @@
         android:scaleType="fitXY"
         app:layout_constraintBottom_toBottomOf="@+id/biometric_icon"
         app:layout_constraintEnd_toEndOf="@+id/biometric_icon"
-        app:layout_constraintHorizontal_bias="1.0"
         app:layout_constraintStart_toStartOf="@+id/biometric_icon"
-        app:layout_constraintTop_toTopOf="@+id/biometric_icon"
-        app:layout_constraintVertical_bias="0.0" />
-
-    <TextView
-        android:id="@+id/title"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:gravity="@integer/biometric_dialog_text_gravity"
-        android:singleLine="true"
-        android:marqueeRepeatLimit="1"
-        android:ellipsize="marquee"
-        style="@style/TextAppearance.AuthCredential.Title"
-        app:layout_constraintBottom_toTopOf="@+id/subtitle"
-        app:layout_constraintEnd_toEndOf="@+id/panel"
-        app:layout_constraintStart_toStartOf="@+id/panel" />
-
-    <TextView
-        android:id="@+id/subtitle"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:gravity="@integer/biometric_dialog_text_gravity"
-        android:singleLine="true"
-        android:marqueeRepeatLimit="1"
-        android:ellipsize="marquee"
-        style="@style/TextAppearance.AuthCredential.Subtitle"
-        app:layout_constraintBottom_toTopOf="@+id/description"
-        app:layout_constraintEnd_toEndOf="@+id/panel"
-        app:layout_constraintStart_toStartOf="@+id/panel" />
-
-    <Space
-        android:id="@+id/space_above_content"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/biometric_prompt_space_above_content"
-        android:visibility="gone"
-        app:layout_constraintTop_toBottomOf="@+id/subtitle"
-        app:layout_constraintEnd_toEndOf="@+id/panel"
-        app:layout_constraintStart_toStartOf="@+id/panel"/>
+        app:layout_constraintTop_toTopOf="@+id/biometric_icon" />
 
     <ScrollView
-        android:id="@+id/customized_view_container"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:fillViewport="true"
-        android:fadeScrollbars="false"
-        android:gravity="center_vertical"
-        android:orientation="vertical"
-        android:paddingHorizontal="@dimen/biometric_prompt_content_container_padding_horizontal"
-        android:scrollbars="vertical"
-        android:visibility="gone"
-        app:layout_constraintTop_toBottomOf="@+id/space_above_content"
-        app:layout_constraintBottom_toTopOf="@+id/biometric_icon"
-        app:layout_constraintEnd_toEndOf="@+id/panel"
-        app:layout_constraintStart_toStartOf="@+id/panel"/>
-
-    <TextView
-        android:id="@+id/description"
-        android:layout_width="wrap_content"
+        android:id="@+id/scrollView"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginBottom="24dp"
-        android:scrollbars="vertical"
-        android:gravity="@integer/biometric_dialog_text_gravity"
-        style="@style/TextAppearance.AuthCredential.Description"
+        android:fillViewport="true"
+        android:padding="16dp"
+        app:layout_constrainedHeight="true"
+        app:layout_constrainedWidth="true"
         app:layout_constraintBottom_toTopOf="@+id/biometric_icon"
-        app:layout_constraintEnd_toEndOf="@+id/panel"
-        app:layout_constraintStart_toStartOf="@+id/panel" />
+        app:layout_constraintEnd_toEndOf="@id/rightGuideline"
+        app:layout_constraintStart_toStartOf="@id/leftGuideline"
+        app:layout_constraintTop_toTopOf="@+id/topGuideline"
+        app:layout_constraintVertical_bias="1.0">
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/innerConstraint"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <ImageView
+                android:id="@+id/logo"
+                android:layout_width="@dimen/biometric_auth_icon_size"
+                android:layout_height="@dimen/biometric_auth_icon_size"
+                android:layout_gravity="center"
+                android:scaleType="fitXY"
+                android:visibility="visible"
+                app:layout_constraintBottom_toTopOf="@+id/logo_description"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toTopOf="parent" />
+
+            <LinearLayout
+                android:id="@+id/customized_view_container"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="center_vertical"
+                android:orientation="vertical"
+                android:paddingHorizontal="@dimen/biometric_prompt_content_container_padding_horizontal"
+                android:visibility="gone"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/subtitle" />
+
+            <Space
+                android:id="@+id/space_above_content"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/biometric_prompt_space_above_content"
+                android:visibility="gone" />
+
+            <TextView
+                android:id="@+id/title"
+                style="@style/TextAppearance.AuthCredential.Title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="@integer/biometric_dialog_text_gravity"
+                app:layout_constraintBottom_toTopOf="@+id/subtitle"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/logo_description" />
+
+            <TextView
+                android:id="@+id/subtitle"
+                style="@style/TextAppearance.AuthCredential.Subtitle"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="@integer/biometric_dialog_text_gravity"
+                app:layout_constraintBottom_toTopOf="@+id/contentBarrier"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/title" />
+
+            <TextView
+                android:id="@+id/logo_description"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:ellipsize="marquee"
+                android:gravity="@integer/biometric_dialog_text_gravity"
+                android:marqueeRepeatLimit="1"
+                android:singleLine="true"
+                app:layout_constraintBottom_toTopOf="@+id/title"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/logo" />
+
+            <TextView
+                android:id="@+id/description"
+                style="@style/TextAppearance.AuthCredential.Description"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="@integer/biometric_dialog_text_gravity"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/subtitle" />
+
+            <androidx.constraintlayout.widget.Barrier
+                android:id="@+id/contentBarrier"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                app:barrierAllowsGoneWidgets="false"
+                app:barrierDirection="top"
+                app:constraint_referenced_ids="description, customized_view_container" />
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+    </ScrollView>
 
     <TextView
         android:id="@+id/indicator"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginTop="16dp"
-        android:gravity="center_horizontal"
-        android:textColor="@color/biometric_dialog_gray"
-        android:textSize="12sp"
         android:accessibilityLiveRegion="polite"
+        android:fadingEdge="horizontal"
+        android:gravity="center_horizontal"
         android:marqueeRepeatLimit="marquee_forever"
         android:scrollHorizontally="true"
-        android:fadingEdge="horizontal"
+        android:textColor="@color/biometric_dialog_gray"
+        android:textSize="12sp"
+        app:layout_constraintBottom_toTopOf="@+id/buttonBarrier"
         app:layout_constraintEnd_toEndOf="@+id/panel"
-        app:layout_constraintHorizontal_bias="0.5"
         app:layout_constraintStart_toStartOf="@+id/panel"
-        app:layout_constraintTop_toBottomOf="@+id/biometric_icon" />
+        app:layout_constraintTop_toBottomOf="@+id/biometric_icon"
+        app:layout_constraintVertical_bias="0.0" />
 
     <!-- Negative Button, reserved for app -->
     <Button
@@ -230,6 +255,22 @@
         app:layout_constraintEnd_toEndOf="@+id/panel" />
 
     <!-- Guidelines for setting panel border -->
+    <androidx.constraintlayout.widget.Barrier
+        android:id="@+id/topBarrier"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:barrierAllowsGoneWidgets="false"
+        app:barrierDirection="top"
+        app:constraint_referenced_ids="scrollView" />
+
+    <androidx.constraintlayout.widget.Barrier
+        android:id="@+id/buttonBarrier"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:barrierAllowsGoneWidgets="false"
+        app:barrierDirection="top"
+        app:constraint_referenced_ids="button_negative, button_cancel, button_use_credential, button_confirm, button_try_again" />
+
     <androidx.constraintlayout.widget.Guideline
         android:id="@+id/leftGuideline"
         android:layout_width="wrap_content"
@@ -251,4 +292,11 @@
         android:orientation="horizontal"
         app:layout_constraintGuide_end="@dimen/biometric_dialog_border_padding" />
 
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/topGuideline"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:orientation="horizontal"
+        app:layout_constraintGuide_percent="0.25171" />
+
 </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/biometric_prompt_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_layout.xml
index e759074..9842109 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_layout.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_layout.xml
@@ -70,7 +70,7 @@
         android:layout_height="@dimen/biometric_prompt_space_above_content"
         android:visibility="gone" />
 
-    <ScrollView
+    <LinearLayout
         android:id="@+id/customized_view_container"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index 1365a11..22d156d 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -263,8 +263,9 @@
                         android:layout_gravity="center_vertical|start">
                         <ImageView
                             android:id="@+id/wifi_connected_icon"
-                            android:layout_width="wrap_content"
-                            android:layout_height="wrap_content"
+                            android:layout_width="match_parent"
+                            android:layout_height="match_parent"
+                            android:scaleType="fitCenter"
                             android:layout_gravity="center"/>
                     </FrameLayout>
 
diff --git a/packages/SystemUI/res/layout/internet_list_item.xml b/packages/SystemUI/res/layout/internet_list_item.xml
index f6a2136..0da0f2b 100644
--- a/packages/SystemUI/res/layout/internet_list_item.xml
+++ b/packages/SystemUI/res/layout/internet_list_item.xml
@@ -35,8 +35,9 @@
             android:layout_gravity="center_vertical|start">
             <ImageView
                 android:id="@+id/wifi_icon"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:scaleType="fitCenter"
                 android:layout_gravity="center"/>
         </FrameLayout>
 
diff --git a/packages/SystemUI/res/layout/notif_half_shelf.xml b/packages/SystemUI/res/layout/notif_half_shelf.xml
index 68c8dd9..d8d2985 100644
--- a/packages/SystemUI/res/layout/notif_half_shelf.xml
+++ b/packages/SystemUI/res/layout/notif_half_shelf.xml
@@ -19,11 +19,11 @@
         xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
         android:id="@+id/half_shelf_dialog"
         android:orientation="vertical"
-        android:layout_width="wrap_content"
+        android:layout_width="@dimen/large_dialog_width"
         android:layout_height="wrap_content"
         android:layout_gravity="center_horizontal|bottom"
-        android:paddingStart="4dp"
-        android:paddingEnd="4dp">
+        android:paddingLeft="@dimen/dialog_side_padding"
+        android:paddingRight="@dimen/dialog_side_padding">
 
     <LinearLayout
         android:id="@+id/half_shelf"
diff --git a/packages/SystemUI/res/layout/scene_window_root.xml b/packages/SystemUI/res/layout/scene_window_root.xml
index bb8de4c..0dcd15b 100644
--- a/packages/SystemUI/res/layout/scene_window_root.xml
+++ b/packages/SystemUI/res/layout/scene_window_root.xml
@@ -24,7 +24,7 @@
     android:id="@+id/scene_window_root"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:fitsSystemWindows="false">
+    android:fitsSystemWindows="true">
 
     <include layout="@layout/super_notification_shade"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/shutdown_dialog_finder_active.xml b/packages/SystemUI/res/layout/shutdown_dialog_finder_active.xml
new file mode 100644
index 0000000..b6db7fc
--- /dev/null
+++ b/packages/SystemUI/res/layout/shutdown_dialog_finder_active.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@android:id/text1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="24dp"
+        android:fontFamily="google-sans"
+        android:gravity="center"
+        android:text="@string/shutdown_progress"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textDirection="locale"
+        android:textSize="18sp"
+        android:visibility="gone"
+        app:layout_constraintBottom_toTopOf="@android:id/text2"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_bias="0.375"
+        app:layout_constraintVertical_chainStyle="packed" />
+
+    <TextView
+        android:id="@android:id/text2"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="24dp"
+        android:fontFamily="google-sans"
+        android:gravity="center"
+        android:text="@string/shutdown_progress"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:textDirection="locale"
+        android:textSize="24sp"
+        app:layout_constraintBottom_toTopOf="@android:id/progress"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@android:id/text1" />
+
+    <ProgressBar
+        android:id="@android:id/progress"
+        style="?android:attr/progressBarStyleLarge"
+        android:layout_width="30dp"
+        android:layout_height="30dp"
+        android:importantForAccessibility="no"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@android:id/text2" />
+
+    <TextView
+        android:id="@+id/finer_hint"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="32dp"
+        android:background="@drawable/bg_shutdown_finder_message"
+        android:drawablePadding="16dp"
+        android:drawableStart="@drawable/ic_finder_active"
+        android:fontFamily="google-sans"
+        android:gravity="start"
+        android:padding="20dp"
+        android:text="@string/finder_active"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:textColor="@android:color/secondary_text_dark"
+        android:textDirection="locale"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@android:id/progress"
+        app:layout_constraintVertical_bias="1" />
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 4002517..515ef61 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Voeg meer legstukke by"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Langdruk om legstukke te pasmaak"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Pasmaak legstukke"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Wysig legstuk"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Verwyder"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Voeg legstuk by"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Lui"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibreer"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Demp"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Saai uit"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Onbeskikbaar omdat luitoon gedemp is"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tik om te ontdemp."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tik om op vibreer te stel. Toeganklikheidsdienste kan dalk gedemp wees."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tik om te demp. Toeganklikheidsdienste kan dalk gedemp wees."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tik om op vibreer te stel."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tik om te demp."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Geraasbeheer"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Tik om luiermodus te verander"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"demp"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ontdemp"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Aan/af-kieslys"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Bladsy <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Sluitskerm"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Sien versorgingstappe"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Sien versorgingstappe"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Prop jou toestel uit"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Maak notas"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Maak notas, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Deel tans oudio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Uitsaai"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hou op om <xliff:g id="APP_NAME">%1$s</xliff:g> uit te saai?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"As jy <xliff:g id="SWITCHAPP">%1$s</xliff:g> uitsaai of die uitvoer verander, sal jou huidige uitsending stop"</string>
diff --git a/packages/SystemUI/res/values-af/tiles_states_strings.xml b/packages/SystemUI/res/values-af/tiles_states_strings.xml
index 662aa71..1c9a7941 100644
--- a/packages/SystemUI/res/values-af/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-af/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Af"</item>
     <item msgid="578444932039713369">"Aan"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Onbeskikbaar"</item>
     <item msgid="8707481475312432575">"Af"</item>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index ebc2002..9763ff2 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ተጨማሪ ምግብሮችን ያክሉ"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ምግብሮችን ለማበጀት በረጅሙ ይጫኑ"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ምግብሮችን አብጅ"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"ምግብርን አርትዕ"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"አስወግድ"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ምግብር አክል"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"ጥሪ"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"ንዘር"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"ድምጸ-ከል አድርግ"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Cast"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"የጥሪ ድምጽ ስለተዘጋ አይገኝም"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s። ወደ ንዝረት ለማቀናበር መታ ያድርጉ። የተደራሽነት አገልግሎቶች ድምጸ-ከል ሊደረግባቸው ይችላል።"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ። የተደራሽነት አገልግሎቶች ድምጸ-ከል ሊደረግባቸው ይችላል።"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s። ወደ ንዝረት ለማቀናበር መታ ያድርጉ።"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ።"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"የጫጫታ መቆጣጠሪያ"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"የደዋይ ሁነታን ለመቀየር መታ ያድርጉ"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ድምጸ-ከል አድርግ"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ድምጸ-ከልን አንሳ"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"የኃይል ምናሌ"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"ገፅ <xliff:g id="ID_1">%1$d</xliff:g> ከ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"ማያ ገፅ ቁልፍ"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"የእንክብካቤ ደረጃዎችን ይመልከቱ"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"የእንክብካቤ ደረጃዎችን ይመልከቱ"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"መሣሪያዎን ይንቀሉ"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>፣ <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"የማስታወሻ አያያዝ"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"የማስታወሻ አያያዝ፣ <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"ኦዲዮ በማጋራት ላይ"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"በማሰራጨት ላይ"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g>ን ማሰራጨት ይቁም?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g>ን ካሰራጩ ወይም ውፅዓትን ከቀየሩ የአሁኑ ስርጭትዎ ይቆማል"</string>
diff --git a/packages/SystemUI/res/values-am/tiles_states_strings.xml b/packages/SystemUI/res/values-am/tiles_states_strings.xml
index e5d68d9..3fb24b9 100644
--- a/packages/SystemUI/res/values-am/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-am/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"ጠፍቷል"</item>
     <item msgid="578444932039713369">"በርቷል"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"አይገኝም"</item>
     <item msgid="8707481475312432575">"ጠፍቷል"</item>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index ec72578..1b7e303 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"إضافة المزيد من التطبيقات المصغّرة"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"اضغط مع الاستمرار لتخصيص التطبيقات المصغّرة."</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"تخصيص التطبيقات المصغَّرة"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"تعديل التطبيق المصغَّر"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"إزالة"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"إضافة تطبيق مصغّر"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"استصدار رنين"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"اهتزاز"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"كتم الصوت"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"البثّ"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"يتعذّر التغيير بسبب كتم صوت الرنين."</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"‏%1$s. انقر لإلغاء التجاهل."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"‏%1$s. انقر للتعيين على الاهتزاز. قد يتم تجاهل خدمات \"سهولة الاستخدام\"."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏%1$s. انقر للتجاهل. قد يتم تجاهل خدمات \"سهولة الاستخدام\"."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‏%1$s. انقر للتعيين على الاهتزاز."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‏%1$s. انقر لكتم الصوت."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"التحكُّم في مستوى الضجيج"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"انقر لتغيير وضع الرنين."</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"كتم الصوت"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"إعادة الصوت"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"قائمة زر التشغيل"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"الصفحة <xliff:g id="ID_1">%1$d</xliff:g> من <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"شاشة القفل"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"الاطّلاع على خطوات العناية"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"الاطّلاع على خطوات العناية"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"افصِل جهازك"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>، <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"تدوين الملاحظات"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"تدوين الملاحظات في \"<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>\""</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"تتم مشاركة الصوت"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"البث"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"هل تريد إيقاف بث تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g>؟"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"إذا أجريت بث تطبيق <xliff:g id="SWITCHAPP">%1$s</xliff:g> أو غيَّرت جهاز الإخراج، سيتوقَف البث الحالي."</string>
diff --git a/packages/SystemUI/res/values-ar/tiles_states_strings.xml b/packages/SystemUI/res/values-ar/tiles_states_strings.xml
index 856ae1d..cf050ac 100644
--- a/packages/SystemUI/res/values-ar/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ar/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"الميزة غير مفعّلة"</item>
     <item msgid="578444932039713369">"الميزة مفعّلة"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"الميزة غير متاحة"</item>
     <item msgid="8707481475312432575">"الميزة غير مفعّلة"</item>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index f66650b..429f03e 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"অধিক ৱিজেট যোগ দিয়ক"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ৱিজেট কাষ্টমাইজ কৰিবলৈ দীঘলীয়াকৈ টিপক"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ৱিজেট কাষ্টমাইজ কৰক"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"ৱিজেট সম্পাদনা কৰক"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"আঁতৰাওক"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ৱিজেট যোগ দিয়ক"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"ৰিং"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"কম্পন"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"মিউট"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"কাষ্ট কৰক"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"ৰিং মিউট কৰি থোৱাৰ বাবে উপলব্ধ নহয়"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s। আনমিউট কৰিবৰ বাবে টিপক।"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s। কম্পনৰ বাবে টিপক। দিব্য়াংগসকলৰ বাবে থকা সেৱা মিউট হৈ থাকিব পাৰে।"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। মিউট কৰিবলৈ টিপক। দিব্য়াংগসকলৰ বাবে থকা সেৱা মিউট হৈ থাকিব পাৰে।"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। কম্পন অৱস্থাত ছেট কৰিবলৈ টিপক।"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। মিউট কৰিবলৈ টিপক।"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"কোলাহল নিয়ন্ত্ৰণ"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"ৰিংগাৰ ম’ড সলনি কৰিবলৈ টিপক"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"মিউট কৰক"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"আনমিউট কৰক"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"পাৱাৰ মেনু"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>ৰ পৃষ্ঠা <xliff:g id="ID_1">%1$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"লক স্ক্ৰীন"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"যত্ন লোৱাৰ পদক্ষেপসমূহ চাওক"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"যত্ন লোৱাৰ পদক্ষেপসমূহ চাওক"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"আপোনাৰ ডিভাইচটো আনপ্লাগ কৰক"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"টোকা গ্ৰহণ কৰা"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"টোকা গ্ৰহণ কৰা, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"অডিঅ’ শ্বেয়াৰ কৰি থকা হৈছে"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"সম্প্ৰচাৰণ"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ সম্প্ৰচাৰ কৰা বন্ধ কৰিবনে?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"যদি আপুনি <xliff:g id="SWITCHAPP">%1$s</xliff:g>ৰ সম্প্ৰচাৰ কৰে অথবা আউটপুট সলনি কৰে, তেন্তে, আপোনাৰ বৰ্তমানৰ সম্প্ৰচাৰ বন্ধ হৈ যাব"</string>
diff --git a/packages/SystemUI/res/values-as/tiles_states_strings.xml b/packages/SystemUI/res/values-as/tiles_states_strings.xml
index a9c3e3b..f4268ed 100644
--- a/packages/SystemUI/res/values-as/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-as/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"অফ আছে"</item>
     <item msgid="578444932039713369">"অন কৰা আছে"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"উপলব্ধ নহয়"</item>
     <item msgid="8707481475312432575">"অফ আছে"</item>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 7048441..639cbbc 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Vidcetlər əlavə edin"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Basıb saxlayaraq vidcetləri fərdiləşdirin"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Vidcetləri fərdiləşdirin"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Vidceti redaktə edin"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Silin"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Vidcet əlavə edin"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Zəng"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibrasiya"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Susdurun"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Yayım"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Zəng səssiz edildiyi üçün əlçatan deyil"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Səsli etmək üçün tıklayın."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Vibrasiyanı ayarlamaq üçün tıklayın. Əlçatımlılıq xidmətləri səssiz edilmiş ola bilər."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Səssiz etmək üçün tıklayın. Əlçatımlılıq xidmətləri səssiz edilmiş ola bilər."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Vibrasiyanı ayarlamaq üçün klikləyin."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Səssiz etmək üçün klikləyin."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Səs-küy idarəsi"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Zəng rejimini dəyişmək üçün toxunun"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"susdurun"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"səssiz rejimdən çıxarın"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Qidalanma düyməsi menyusu"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> səhifədən <xliff:g id="ID_1">%1$d</xliff:g> səhifə"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Ekran kilidi"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ehtiyat tədbiri mərhələlərinə baxın"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ehtiyat tədbiri mərhələlərinə baxın"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Cihazınızı ayırın"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Qeydgötürmə"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Qeydgötürmə, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Audio paylaşılır"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Yayım"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqinin yayımlanması dayandırılsın?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> tətbiqini yayımlasanız və ya nəticəni dəyişsəniz, cari yayımınız dayandırılacaq"</string>
diff --git a/packages/SystemUI/res/values-az/tiles_states_strings.xml b/packages/SystemUI/res/values-az/tiles_states_strings.xml
index d973e4e..eeb81cc 100644
--- a/packages/SystemUI/res/values-az/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-az/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Deaktiv"</item>
     <item msgid="578444932039713369">"Aktiv"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Əlçatan deyil"</item>
     <item msgid="8707481475312432575">"Deaktiv"</item>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index a598d8f..e97dbec 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodajte još vidžeta"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dugi pritisak za prilagođavanje vidžeta"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prilagodi vidžete"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Izmeni vidžet"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Ukloni"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj vidžet"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Aktiviraj zvono"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibriraj"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Isključi zvuk"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Prebacivanje"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nedostupno jer je zvuk isključen"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Dodirnite da biste uključili zvuk."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Dodirnite da biste podesili na vibraciju. Zvuk usluga pristupačnosti će možda biti isključen."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da biste isključili zvuk. Zvuk usluga pristupačnosti će možda biti isključen."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dodirnite da biste podesili na vibraciju."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dodirnite da biste isključili zvuk."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Kontrola šuma"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Dodirnite da biste promenili režim zvona"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključite zvuk"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključite zvuk"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Meni dugmeta za uključivanje"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. strana od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Zaključan ekran"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Pogledajte upozorenja"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pogledajte upozorenja"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Isključite uređaj"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Pravljenje beležaka"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Pravljenje beležaka, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Deli se zvuk"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitovanje"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Želite da zaustavite emitovanje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ako emitujete aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g> ili promenite izlaz, aktuelno emitovanje će se zaustaviti"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml b/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
index 32051ef..217d999 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Isključeno"</item>
     <item msgid="578444932039713369">"Uključeno"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Nedostupno"</item>
     <item msgid="8707481475312432575">"Isključeno"</item>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 2b137fb..3b06d05 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Дадаць іншыя віджэты"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Доўга націскайце, каб наладзіць віджэты"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Наладзіць віджэты"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Змяніць віджэт"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Выдаліць"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Дадаць віджэт"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Званок"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Вібрацыя"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Гук выключаны"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Трансляцыя"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Недаступна, бо выключаны гук выклікаў"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Дакраніцеся, каб уключыць гук."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Дакраніцеся, каб уключыць вібрацыю. Можа быць адключаны гук службаў спецыяльных магчымасцей."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Дакраніцеся, каб адключыць гук. Можа быць адключаны гук службаў спецыяльных магчымасцей."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Дакраніцеся, каб уключыць вібрацыю."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Дакраніцеся, каб адключыць гук"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Кантроль шуму"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Націсніце, каб змяніць рэжым званка"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"выключыць гук"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"уключыць гук"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Меню кнопкі сілкавання"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Старонка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Экран блакіроўкі"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Глядзець паэтапную дапамогу"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Глядзець паэтапную дапамогу"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Адключыце прыладу"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Стварэнне нататак"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Стварэнне нататак, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Ідзе абагульванне аўдыя"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Перадача даных"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Спыніць трансляцыю праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Пры пераключэнні на праграму \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\" ці змяненні вываду бягучая трансляцыя спыняецца"</string>
diff --git a/packages/SystemUI/res/values-be/tiles_states_strings.xml b/packages/SystemUI/res/values-be/tiles_states_strings.xml
index e71c29b..717e4c9 100644
--- a/packages/SystemUI/res/values-be/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-be/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Выключана"</item>
     <item msgid="578444932039713369">"Уключана"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Недаступна"</item>
     <item msgid="8707481475312432575">"Выключана"</item>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index aa3da9c..643ef9c 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Добавете още приспособления"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Натиснете продължително за персонализ. на приспос."</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Персонализиране на приспособленията"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Редактиране на приспособлението"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Премахване"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Добавяне на приспособление"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Позвъняване"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Вибриране"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Без звук"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Предаване"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Не е налице, защото звъненето е спряно"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Докоснете, за да включите отново звука."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Докоснете, за да зададете вибриране. Възможно е звукът на услугите за достъпност да бъде заглушен."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Докоснете, за да заглушите звука. Възможно е звукът на услугите за достъпност да бъде заглушен."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Докоснете, за да зададете вибриране."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Докоснете, за да заглушите звука."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Управление на шума"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Докоснете, за да промените режима на звънене"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"спиране"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"пускане"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Меню за включване/изключване"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Страница <xliff:g id="ID_1">%1$d</xliff:g> от <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Заключен екран"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Вижте стъпките, които да предприемете"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Вижте стъпките, които да предприемете"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Изключете устройството си"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Водене на бележки"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Водене на бележки, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Споделя аудио"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Излъчване"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Да се спре ли предаването на <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ако предавате <xliff:g id="SWITCHAPP">%1$s</xliff:g> или промените изхода, текущото ви предаване ще бъде прекратено"</string>
diff --git a/packages/SystemUI/res/values-bg/tiles_states_strings.xml b/packages/SystemUI/res/values-bg/tiles_states_strings.xml
index 24b41d2..58fa82b 100644
--- a/packages/SystemUI/res/values-bg/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bg/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Изкл."</item>
     <item msgid="578444932039713369">"Вкл."</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Не е налице"</item>
     <item msgid="8707481475312432575">"Изкл."</item>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 12e24c0..9a2f040 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"আরও উইজেট যোগ করুন"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"উইজেট কাস্টমাইজ করতে বেশিক্ষণ প্রেস করুন"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"উইজেট কাস্টমাইজ করুন"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"উইজেট এডিট করুন"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"সরান"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"উইজেট যোগ করুন"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"রিং"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"ভাইব্রেট"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"মিউট"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"কাস্ট করুন"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"রিং মিউট করা হয়েছে বলে উপলভ্য নেই"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s। সশব্দ করতে আলতো চাপুন।"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s। কম্পন এ সেট করতে আলতো চাপুন। অ্যাক্সেসযোগ্যতার পরিষেবাগুলিকে মিউট করা হতে পারে।"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। মিউট করতে আলতো চাপুন। অ্যাক্সেসযোগ্যতার পরিষেবাগুলিকে মিউট করা হতে পারে।"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। ভাইব্রেট করতে ট্যাপ করুন।"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। মিউট করতে ট্যাপ করুন।"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"আশপাশের আওয়াজ কন্ট্রোল করা"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"রিঙ্গার মোড পরিবর্তন করতে ট্যাপ করুন"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"মিউট করুন"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"আনমিউট করুন"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"পাওয়ার মেনু"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>টির মধ্যে <xliff:g id="ID_1">%1$d</xliff:g> নং পৃষ্ঠা"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"লক স্ক্রিন"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ডিভাইস রক্ষণাবেক্ষণের ধাপগুলি দেখুন"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ডিভাইস রক্ষণাবেক্ষণের ধাপগুলি দেখুন"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"আপনার ডিভাইস আনপ্লাগ করা"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"নোট নেওয়া"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"নোট নেওয়া, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"অডিও শেয়ার করা হচ্ছে"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ব্রডকাস্ট করা হচ্ছে"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> সম্প্রচার বন্ধ করবেন?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"আপনি <xliff:g id="SWITCHAPP">%1$s</xliff:g> সম্প্রচার করলে বা আউটপুট পরিবর্তন করলে, আপনার বর্তমান সম্প্রচার বন্ধ হয়ে যাবে"</string>
diff --git a/packages/SystemUI/res/values-bn/tiles_states_strings.xml b/packages/SystemUI/res/values-bn/tiles_states_strings.xml
index 59061c2..5c3c66c 100644
--- a/packages/SystemUI/res/values-bn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bn/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"বন্ধ আছে"</item>
     <item msgid="578444932039713369">"চালু আছে"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"উপলভ্য নেই"</item>
     <item msgid="8707481475312432575">"বন্ধ আছে"</item>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index f79e2d9..db102a0 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodajte još vidžeta"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pritisnite i zadržite da prilagodite vidžete"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prilagodite vidžete"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Uredite vidžet"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Uklanjanje"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodajte vidžet"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Zvono"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibriranje"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Isključi zvuk"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Emitiraj"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nedostupno zbog isključenog zvona"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Dodirnite da uključite zvukove."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Dodirnite za postavljanje vibracije. Zvukovi usluga pristupačnosti mogu biti isključeni."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da isključite zvuk. Zvukovi usluga pristupačnosti mogu biti isključeni."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dodirnite da postavite vibraciju."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dodirnite da isključite zvuk."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Upravljanje bukom"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Dodirnite da promijenite način rada zvuka zvona"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključite zvuk"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključite zvuk"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Meni napajanja"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Zaključani ekran"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Pogledajte korake za zaštitu"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pogledajte korake za zaštitu"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Iskopčajte uređaj"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Pisanje bilješki"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Pisanje bilješki, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Dijeljenje zvuka"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitiranje"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zaustaviti emitiranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ako emitirate aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g> ili promijenite izlaz, trenutno emitiranje će se zaustaviti"</string>
diff --git a/packages/SystemUI/res/values-bs/tiles_states_strings.xml b/packages/SystemUI/res/values-bs/tiles_states_strings.xml
index 32051ef..217d999 100644
--- a/packages/SystemUI/res/values-bs/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bs/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Isključeno"</item>
     <item msgid="578444932039713369">"Uključeno"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Nedostupno"</item>
     <item msgid="8707481475312432575">"Isključeno"</item>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 583275f..c528734 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Afegeix més widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén premut per personalitzar els widgets"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalitza els widgets"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Edita el widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Suprimeix"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Afegeix un widget"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Fes sonar"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibra"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Silencia"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Emet"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"No disponible perquè el so està silenciat"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toca per activar el so."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toca per activar la vibració. Pot ser que els serveis d\'accessibilitat se silenciïn."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca per silenciar el so. Pot ser que els serveis d\'accessibilitat se silenciïn."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toca per activar la vibració."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toca per silenciar."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Control de soroll"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Toca per canviar el mode de timbre"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"deixar de silenciar"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menú d\'engegada"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Pàgina <xliff:g id="ID_1">%1$d</xliff:g> (<xliff:g id="ID_2">%2$d</xliff:g> en total)"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Pantalla de bloqueig"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Mostra els passos de manteniment"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Mostra els passos de manteniment"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Desconnecta el dispositiu"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Presa de notes"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Presa de notes, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"S\'està compartint l\'àudio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"S\'està emetent"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vols deixar d\'emetre <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si emets <xliff:g id="SWITCHAPP">%1$s</xliff:g> o canvies la sortida, l\'emissió actual s\'aturarà"</string>
diff --git a/packages/SystemUI/res/values-ca/tiles_states_strings.xml b/packages/SystemUI/res/values-ca/tiles_states_strings.xml
index e99926c..c1ac5a3 100644
--- a/packages/SystemUI/res/values-ca/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ca/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Desactivat"</item>
     <item msgid="578444932039713369">"Activat"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"No disponible"</item>
     <item msgid="8707481475312432575">"Desactivat"</item>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 6cdb3d8..f29dabb 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Přidat další widgety"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dlouhým stisknutím můžete přizpůsobit widgety"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Přizpůsobit widgety"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Upravit widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Odstranit"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Přidat widget"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Vyzvánění"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibrace"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Ztlumení"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Odesílání"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nedostupné, protože vyzvánění je ztlumené"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Klepnutím zapnete zvuk."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Klepnutím aktivujete režim vibrací. Služby přístupnosti mohou být ztlumeny."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Klepnutím vypnete zvuk. Služby přístupnosti mohou být ztlumeny."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Klepnutím nastavíte vibrace."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Klepnutím vypnete zvuk."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Omezení hluku"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Klepnutím změníte režim vyzvánění"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vypnout zvuk"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"zapnout zvuk"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Nabídka vypínače"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Stránka <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Obrazovka uzamčení"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Zobrazit pokyny, co dělat"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobrazit pokyny, co dělat"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Odpojte zařízení"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g> <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Psaní poznámek"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Psaní poznámek, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Sdílení zvuku"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Vysílání"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zastavit vysílání v aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Pokud budete vysílat v aplikaci <xliff:g id="SWITCHAPP">%1$s</xliff:g> nebo změníte výstup, aktuální vysílání se zastaví"</string>
diff --git a/packages/SystemUI/res/values-cs/tiles_states_strings.xml b/packages/SystemUI/res/values-cs/tiles_states_strings.xml
index 6359f94..0a4d4d0 100644
--- a/packages/SystemUI/res/values-cs/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-cs/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Vypnuto"</item>
     <item msgid="578444932039713369">"Zapnuto"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Nedostupné"</item>
     <item msgid="8707481475312432575">"Vypnuto"</item>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 79b01a8..ec899f2 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Tilføj flere widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Hold fingeren nede for at tilpasse widgets"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Tilpas widgets"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Rediger widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Fjern"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tilføj widget"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Ring"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibration"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Slå lyden fra"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Cast"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Ikke muligt, da ringetonen er slået fra"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tryk for at slå lyden til."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tryk for at konfigurere til at vibrere. Tilgængelighedstjenester kan blive deaktiveret."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tryk for at slå lyden fra. Lyden i tilgængelighedstjenester kan blive slået fra."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tryk for at aktivere vibration."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tryk for at slå lyden fra."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Støjstyring"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Tryk for at ændre ringetilstand"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"slå lyden fra"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå lyden til"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu for afbryderknappen"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Side <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Låseskærm"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Se håndteringsvejledning"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Se håndteringsvejledning"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Træk stikket ud af din enhed"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Notetagning"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Notetagning, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Deler lyd"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Udsender"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop udsendelsen <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Hvis du udsender <xliff:g id="SWITCHAPP">%1$s</xliff:g> eller skifter output, stopper din aktuelle udsendelse"</string>
diff --git a/packages/SystemUI/res/values-da/tiles_states_strings.xml b/packages/SystemUI/res/values-da/tiles_states_strings.xml
index 1daed4c..2391753 100644
--- a/packages/SystemUI/res/values-da/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-da/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Fra"</item>
     <item msgid="578444932039713369">"Til"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Ikke tilgængelig"</item>
     <item msgid="8707481475312432575">"Fra"</item>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 43f799b..f7e74c9 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Weitere Widgets hinzufügen"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Lange drücken, um Widgets anzupassen"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Widgets anpassen"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Widget bearbeiten"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Entfernen"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget hinzufügen"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Klingeln lassen"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibrieren"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Stummschalten"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Stream"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nicht verfügbar, da Klingelton stumm"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Zum Aufheben der Stummschaltung tippen."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tippen, um Vibrieren festzulegen. Bedienungshilfen werden unter Umständen stummgeschaltet."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Zum Stummschalten tippen. Bedienungshilfen werden unter Umständen stummgeschaltet."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Zum Aktivieren der Vibration tippen."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Zum Stummschalten tippen."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Geräuschunterdrückung"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Zum Ändern des Klingeltonmodus tippen"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"Stummschalten"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"Aufheben der Stummschaltung"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Ein-/Aus-Menü"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Seite <xliff:g id="ID_1">%1$d</xliff:g> von <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Sperrbildschirm"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Schritte zur Abkühlung des Geräts ansehen"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Schritte zur Abkühlung des Geräts ansehen"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Gerät vom Stromnetz trennen"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Notizen"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Notizen, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Audio wird geteilt"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Übertragung läuft"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> nicht mehr streamen?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Wenn du <xliff:g id="SWITCHAPP">%1$s</xliff:g> streamst oder die Ausgabe änderst, wird dein aktueller Stream beendet"</string>
diff --git a/packages/SystemUI/res/values-de/tiles_states_strings.xml b/packages/SystemUI/res/values-de/tiles_states_strings.xml
index 9a08747..3aae04b 100644
--- a/packages/SystemUI/res/values-de/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-de/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Aus"</item>
     <item msgid="578444932039713369">"An"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Nicht verfügbar"</item>
     <item msgid="8707481475312432575">"Aus"</item>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 43ab777..6b341fd 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Προσθήκη περισσότερων γραφικών στοιχείων"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Παρατεταμένο πάτημα για προσαρμογή γραφ. στοιχείων"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Προσαρμογή γραφικών στοιχείων"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Επεξεργασία γραφικού στοιχείου"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Κατάργηση"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Προσθήκη γραφικού στοιχείου"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Κουδούνισμα"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Δόνηση"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Σίγαση"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Μετάδοση"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Μη διαθέσιμο λόγω σίγασης ήχου κλήσης"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Πατήστε για κατάργηση σίγασης."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Πατήστε για ενεργοποιήσετε τη δόνηση. Οι υπηρεσίες προσβασιμότητας ενδέχεται να τεθούν σε σίγαση."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Πατήστε για σίγαση. Οι υπηρεσίες προσβασιμότητας ενδέχεται να τεθούν σε σίγαση."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Πατήστε για να ενεργοποιήσετε τη δόνηση."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Πατήστε για σίγαση."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Έλεγχος θορύβου"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Πατήστε για να αλλάξετε τη λειτουργία ειδοποίησης ήχου"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"σίγαση"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"κατάργηση σίγασης"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Μενού λειτουργίας"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Σελίδα <xliff:g id="ID_1">%1$d</xliff:g> από <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Οθόνη κλειδώματος"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Δείτε βήματα αντιμετώπισης."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Δείτε βήματα αντιμετώπισης."</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Αποσυνδέστε τη συσκευή"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Δημιουργία σημειώσεων"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Δημιουργία σημειώσεων, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Κοινοποίηση ήχου"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Μετάδοση"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Διακοπή μετάδοσης με την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Εάν κάνετε μετάδοση με την εφαρμογή <xliff:g id="SWITCHAPP">%1$s</xliff:g> ή αλλάξετε την έξοδο, η τρέχουσα μετάδοση θα σταματήσει"</string>
diff --git a/packages/SystemUI/res/values-el/tiles_states_strings.xml b/packages/SystemUI/res/values-el/tiles_states_strings.xml
index 4d94515..035f117 100644
--- a/packages/SystemUI/res/values-el/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-el/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Ανενεργό"</item>
     <item msgid="578444932039713369">"Ενεργό"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Μη διαθέσιμο"</item>
     <item msgid="8707481475312432575">"Ανενεργό"</item>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 9d2742a..021f7db 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -429,6 +429,7 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Customise widgets"</string>
+    <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App icon for disabled widget"</string>
     <string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string>
@@ -573,11 +574,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Ring"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibrate"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Mute"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Cast"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Unavailable because ring is muted"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tap to unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tap to set to vibrate."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tap to mute."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Noise control"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string>
@@ -832,6 +836,8 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string>
+    <string name="finder_active" msgid="7907846989716941952">"You can locate this phone with Find My Device even when powered off"</string>
+    <string name="shutdown_progress" msgid="5464239146561542178">"Shutting down…"</string>
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"See care steps"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
@@ -1186,6 +1192,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Note-taking"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Note-taking, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Sharing audio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Broadcasting"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
index 0cf2868..2576b60 100644
--- a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Off"</item>
     <item msgid="578444932039713369">"On"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Unavailable"</item>
     <item msgid="8707481475312432575">"Off"</item>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index f77f660..14cb7a0 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -429,6 +429,7 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customize widgets"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Customize widgets"</string>
+    <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App icon for disabled widget"</string>
     <string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string>
@@ -573,11 +574,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Ring"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibrate"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Mute"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Cast"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Unavailable because ring is muted"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tap to unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tap to set to vibrate."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tap to mute."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Noise Control"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string>
@@ -832,6 +836,8 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string>
+    <string name="finder_active" msgid="7907846989716941952">"You can locate this phone with Find My Device even when powered off"</string>
+    <string name="shutdown_progress" msgid="5464239146561542178">"Shutting down…"</string>
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"See care steps"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
@@ -1186,6 +1192,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Note-taking"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Note-taking, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Sharing audio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Broadcasting"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
index 0cf2868..2576b60 100644
--- a/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Off"</item>
     <item msgid="578444932039713369">"On"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Unavailable"</item>
     <item msgid="8707481475312432575">"Off"</item>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 9d2742a..021f7db 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -429,6 +429,7 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Customise widgets"</string>
+    <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App icon for disabled widget"</string>
     <string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string>
@@ -573,11 +574,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Ring"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibrate"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Mute"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Cast"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Unavailable because ring is muted"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tap to unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tap to set to vibrate."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tap to mute."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Noise control"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string>
@@ -832,6 +836,8 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string>
+    <string name="finder_active" msgid="7907846989716941952">"You can locate this phone with Find My Device even when powered off"</string>
+    <string name="shutdown_progress" msgid="5464239146561542178">"Shutting down…"</string>
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"See care steps"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
@@ -1186,6 +1192,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Note-taking"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Note-taking, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Sharing audio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Broadcasting"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
index 0cf2868..2576b60 100644
--- a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Off"</item>
     <item msgid="578444932039713369">"On"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Unavailable"</item>
     <item msgid="8707481475312432575">"Off"</item>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 9d2742a..021f7db 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -429,6 +429,7 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Customise widgets"</string>
+    <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App icon for disabled widget"</string>
     <string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string>
@@ -573,11 +574,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Ring"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibrate"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Mute"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Cast"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Unavailable because ring is muted"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tap to unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tap to set to vibrate."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tap to mute."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Noise control"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string>
@@ -832,6 +836,8 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string>
+    <string name="finder_active" msgid="7907846989716941952">"You can locate this phone with Find My Device even when powered off"</string>
+    <string name="shutdown_progress" msgid="5464239146561542178">"Shutting down…"</string>
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"See care steps"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
@@ -1186,6 +1192,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Note-taking"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Note-taking, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Sharing audio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Broadcasting"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Stop broadcasting <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"If you broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g> or change the output, your current broadcast will stop"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
index 0cf2868..2576b60 100644
--- a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Off"</item>
     <item msgid="578444932039713369">"On"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Unavailable"</item>
     <item msgid="8707481475312432575">"Off"</item>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 6f5c133..af690e4 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -429,6 +429,7 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‎‎‎‏‏‎‏‎‎‏‎‎‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎Add more widgets‎‏‎‎‏‎"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‏‎‎‏‎‏‎‏‏‏‎‎‏‎‎‎‎‏‎‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎Long press to customize widgets‎‏‎‎‏‎"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎‏‎‏‏‎‏‏‏‏‏‏‏‎‎‎‏‎‏‎Customize widgets‎‏‎‎‏‎"</string>
+    <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‏‎‎‎‏‏‏‏‎‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‎‏‏‎‏‏‎‎‎‏‎‎‎‏‏‏‏‏‎App icon for disabled widget‎‏‎‎‏‎"</string>
     <string name="edit_widget" msgid="9030848101135393954">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‎‎‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‎‎‏‎‎Edit widget‎‏‎‎‏‎"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‏‎‏‎‏‏‎‏‎‏‏‏‎‏‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎Remove‎‏‎‎‏‎"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‎‎‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‏‏‏‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‏‎Add widget‎‏‎‎‏‎"</string>
@@ -573,11 +574,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎‏‎‎‎‎‏‏‎‏‎‏‏‏‎Ring‎‏‎‎‏‎"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‏‏‎‏‎‏‎‏‏‎‎‎‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‏‎‎‎‎‎‏‎‎‎‎‏‎Vibrate‎‏‎‎‏‎"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‏‎‎‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‎‎‎‏‎‏‎‎‎‏‎‎‏‏‎‎‏‏‎Mute‎‏‎‎‏‎"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‏‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‎‎Cast‎‏‎‎‏‎"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‏‏‎Unavailable because ring is muted‎‏‎‎‏‎"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‎‏‎‎‎‏‎%1$s. Tap to unmute.‎‏‎‎‏‎"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‎‎‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎%1$s. Tap to set to vibrate. Accessibility services may be muted.‎‏‎‎‏‎"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‏‎‎‏‏‎‏‏‎‎‎‎%1$s. Tap to mute. Accessibility services may be muted.‎‏‎‎‏‎"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‎‏‏‏‎‏‎‏‏‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎‏‎‏‏‏‏‏‎%1$s. Tap to set to vibrate.‎‏‎‎‏‎"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‏‏‎‏‏‏‎‏‎‎‏‎‎‎‏‎‎‏‎‏‎‏‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‏‏‎‎‎%1$s. Tap to mute.‎‏‎‎‏‎"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‎‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‎‏‎‎‏‎‎‏‏‎‏‎‏‎‏‎‏‏‎‏‎‎Noise Control‎‏‎‎‏‎"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‏‏‎‏‏‎‎‎Tap to change ringer mode‎‏‎‎‏‎"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‎‎‎‏‎‏‏‎‎‏‏‎‏‏‎‏‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‏‏‎‎mute‎‏‎‎‏‎"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‏‏‎‏‎‏‏‏‎‏‎‎‎‏‏‎‏‏‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‎‎unmute‎‏‎‎‏‎"</string>
@@ -832,6 +836,8 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‏‏‏‎‎‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‏‎‎‏‎‏‎‎‎‏‎‎‎‎‎‎‏‎‎‏‏‏‏‏‏‎‎‏‏‎‎‎Power menu‎‏‎‎‏‎"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‎‎‏‏‏‎‎‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‎Page ‎‏‎‎‏‏‎<xliff:g id="ID_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ of ‎‏‎‎‏‏‎<xliff:g id="ID_2">%2$d</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‏‏‏‎‏‏‎‎‏‎‎‎‎‏‎‏‎‎‏‎‏‏‎‏‏‎‏‎‏‏‎‎‎‎‏‎‎‏‏‏‎‎‎‎‎‎Lock screen‎‏‎‎‏‎"</string>
+    <string name="finder_active" msgid="7907846989716941952">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‏‏‏‎‎‏‎‏‎‎‎‎‏‏‏‏‎‎‎‎‏‎‎‎‏‎‎‎‎‎‏‏‏‎‎‎‎‏‏‎‏‏‎‎‏‎‎‎‎‎‎‎‎You can locate this phone with Find My Device even when powered off‎‏‎‎‏‎"</string>
+    <string name="shutdown_progress" msgid="5464239146561542178">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‎‏‎‏‎‎‏‏‏‎‎‎‎‎‏‎‎‎‏‏‎‏‏‎‎‏‎‎‏‎‏‎‎‏‎‏‎‏‏‎‎‏‏‎‎‎‎‎‏‎‎‎‏‎‎Shutting down…‎‏‎‎‏‎"</string>
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‏‎‏‎‎‏‏‎‏‎‎‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‎‎‏‏‏‎‏‎‏‎See care steps‎‏‎‎‏‎"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‎‏‎‏‎‏‎‏‏‏‏‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎See care steps‎‏‎‎‏‎"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‎‏‎Unplug your device‎‏‎‎‏‎"</string>
@@ -1186,6 +1192,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‏‎‏‏‎‏‏‎‎‏‎‏‎‏‏‎‏‏‎‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>‎‏‎‎‏‏‏‎, ‎‏‎‎‏‏‎<xliff:g id="TEMPERATURE">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‎‎‏‎‎‏‎‎‏‏‎‎‎Note-taking‎‏‎‎‏‎"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‏‎‎‎‎‎‏‎‏‎‎‎‎‏‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‏‏‎‎‎‏‎‎‎‎‏‏‏‎‎‎‏‎Note-taking, ‎‏‎‎‏‏‎<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‏‎‎‎‏‎‏‏‎‏‎‏‎‏‎‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‎‎‎Sharing audio‎‏‎‎‏‎"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‏‎‏‎‎‎‎‎‎‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‎‏‎‎‎‏‎‏‏‏‎‏‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‏‎‎Broadcasting‎‏‎‎‏‎"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‏‏‏‎‏‏‏‎‏‎‎‎‏‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‏‏‎‎‏‏‎Stop broadcasting ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎‎‎‏‎‎‎‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‏‏‎‎‏‎‎‎‎‎‎‏‎If you broadcast ‎‏‎‎‏‏‎<xliff:g id="SWITCHAPP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ or change the output, your current broadcast will stop‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
index b9c8e5f..42daf8a 100644
--- a/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‏‏‏‏‎‏‎‏‎‎‏‏‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‏‏‎‏‎‎‏‎‎‏‎‎‏‏‏‏‏‏‎‎‎‏‎Off‎‏‎‎‏‎"</item>
     <item msgid="578444932039713369">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‏‏‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‏‏‎‎‎‎‏‎‏‏‎‏‎‎‎‏‎‎‎‏‎‎‏‎‏‏‎‎‏‎On‎‏‎‎‏‎"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‎‏‏‏‎‎‏‎‎‏‎‎‏‎‎‎‏‎‏‏‎‎‎‏‎‏‎‏‎‎‎‎‏‎‎‏‎‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎Unavailable‎‏‎‎‏‎"</item>
     <item msgid="8707481475312432575">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‎‎‎‎‏‎‎‎‏‎‎‏‎‎‎‎‎‎‎‎‏‎‎‏‎‏‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‏‏‎Off‎‏‎‎‏‎"</item>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 8c64a07..1798e9a 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -429,6 +429,7 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Agregar más widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén presionado para personalizar los widgets"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
+    <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ícono de la app de widget inhabilitado"</string>
     <string name="edit_widget" msgid="9030848101135393954">"Modificar widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Agregar widget"</string>
@@ -573,11 +574,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Timbre"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibrar"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Silenciar"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Transmisión"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"No disponible por timbre silenciado"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Presiona para dejar de silenciar."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Presiona para establecer el modo vibración. Es posible que los servicios de accesibilidad estén silenciados."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Presiona para silenciar. Es posible que los servicios de accesibilidad estén silenciados."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Presiona para establecer el modo vibración."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Presiona para silenciar."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Control de ruido"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Presiona para cambiar el modo de timbre"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"dejar de silenciar"</string>
@@ -832,6 +836,8 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menú de encendido"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Pantalla de bloqueo"</string>
+    <string name="finder_active" msgid="7907846989716941952">"Puedes ubicar este teléfono con Encontrar mi dispositivo, incluso si está apagado"</string>
+    <string name="shutdown_progress" msgid="5464239146561542178">"Apagando…"</string>
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver pasos de mantenimiento"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantenimiento"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Desenchufa el dispositivo"</string>
@@ -1186,6 +1192,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Tomar notas"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Tomar notas, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Compartiendo audio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmitiendo"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"¿Quieres dejar de transmitir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si transmites <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambias la salida, tu transmisión actual se detendrá"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
index bb3983b..09abc54 100644
--- a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Desactivado"</item>
     <item msgid="578444932039713369">"Activado"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"No disponible"</item>
     <item msgid="8707481475312432575">"Desactivado"</item>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 692bb26..73c913f 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Añade más widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén pulsado para personalizar los widgets"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Añadir widget"</string>
@@ -530,7 +532,7 @@
     <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Tu padre o madre gestionan este dispositivo y pueden ver y controlar cierta información, como las aplicaciones que utilizas, tu ubicación y tu tiempo de pantalla."</string>
     <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Desbloqueado por TrustAgent"</string>
-    <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Protección antirrobo\nDispositivo bloqueado; demasiados intentos"</string>
+    <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Protección antirrobo\nDispositivo bloqueado por nº de intentos"</string>
     <string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
     <string name="accessibility_volume_settings" msgid="1458961116951564784">"Ajustes de sonido"</string>
     <string name="volume_odi_captions_tip" msgid="8825655463280990941">"Subtitular automáticamente"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Hacer sonar"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibrar"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Silenciar"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Enviar"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"No disponible (el tono está silenciado)"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toca para activar el sonido."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toca para poner el dispositivo en vibración. Los servicios de accesibilidad pueden silenciarse."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca para silenciar. Los servicios de accesibilidad pueden silenciarse."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toca para activar la vibración."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toca para silenciar."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Control de ruido"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Toca para cambiar el modo de timbre"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"dejar de silenciar"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menú de encendido"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Pantalla de bloqueo"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver pasos de mantenimiento"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantenimiento"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Desenchufa tu dispositivo"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Toma de notas"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Toma de notas, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Compartiendo audio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitiendo"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"¿Dejar de emitir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si emites <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambias la salida, tu emisión actual se detendrá"</string>
diff --git a/packages/SystemUI/res/values-es/tiles_states_strings.xml b/packages/SystemUI/res/values-es/tiles_states_strings.xml
index 66c7ee5..83b4627 100644
--- a/packages/SystemUI/res/values-es/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Desactivado"</item>
     <item msgid="578444932039713369">"Activado"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"No disponible"</item>
     <item msgid="8707481475312432575">"Desactivado"</item>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 070f200..6fa7044 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Lisage rohkem vidinaid"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Vajutage pikalt vidinate kohandamiseks"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Kohanda vidinaid"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Muuda vidinat"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Eemalda"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lisa vidin"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Helisemine"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibreerimine"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Vaigistatud"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Ülekandmine"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Pole saadaval, kuna helin on vaigistatud"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Puudutage vaigistuse tühistamiseks."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Puudutage värinarežiimi määramiseks. Juurdepääsetavuse teenused võidakse vaigistada."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Puudutage vaigistamiseks. Juurdepääsetavuse teenused võidakse vaigistada."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Puudutage vibreerimise määramiseks."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Puudutage vaigistamiseks."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Mürasummutus"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Puudutage telefonihelina režiimi muutmiseks"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vaigistamine"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"vaigistuse tühistamine"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Toitemenüü"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Leht <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Lukustuskuva"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Vaadake hooldusjuhiseid"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Vaadake hooldusjuhiseid"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Eemaldage seade"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Märkmete tegemine"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Märkmete tegemine <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Jagab heli"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Edastamine"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Kas peatada rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> ülekandmine?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Kui kannate rakendust <xliff:g id="SWITCHAPP">%1$s</xliff:g> üle või muudate väljundit, peatatakse teie praegune ülekanne"</string>
diff --git a/packages/SystemUI/res/values-et/tiles_states_strings.xml b/packages/SystemUI/res/values-et/tiles_states_strings.xml
index 6a9edbb..4f0551d 100644
--- a/packages/SystemUI/res/values-et/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-et/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Väljas"</item>
     <item msgid="578444932039713369">"Sees"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Pole saadaval"</item>
     <item msgid="8707481475312432575">"Väljas"</item>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 36eac0c..564fbb3 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -346,7 +346,7 @@
     <string name="qs_record_issue_stop" msgid="3531747965741982657">"Gelditu"</string>
     <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Gailuaren erabileraren zer alderdiri eragin dio?"</string>
     <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Hautatu arazo mota"</string>
-    <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Pantaila-grabagailua"</string>
+    <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Pantaila-grabaketa"</string>
   <string-array name="qs_record_issue_types">
     <item msgid="2947988124014085798">"Errendimendua"</item>
     <item msgid="1627504621139124393">"Erabiltzaile-interfazea"</item>
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Gehitu widget gehiago"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Widgetak pertsonalizatzeko, sakatu luze"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Pertsonalizatu widgetak"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Editatu widgeta"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Kendu"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Gehitu widget bat"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Jo tonua"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Dardara"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Ez jo tonua"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Igorri"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Ez dago erabilgarri, tonua desaktibatuta dagoelako"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Sakatu audioa aktibatzeko."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Sakatu dardara ezartzeko. Baliteke erabilerraztasun-eginbideen audioa desaktibatzea."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Sakatu audioa desaktibatzeko. Baliteke erabilerraztasun-eginbideen audioa desaktibatzea."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Sakatu hau dardara ezartzeko."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Sakatu hau audioa desaktibatzeko."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Zarata-murrizketa"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Sakatu tonu-jotzailearen modua aldatzeko"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desaktibatu audioa"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktibatu audioa"</string>
@@ -725,7 +730,7 @@
     <string name="group_system_full_screenshot" msgid="5742204844232667785">"Atera pantaila-argazki bat"</string>
     <string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"Erakutsi lasterbideak"</string>
     <string name="group_system_go_back" msgid="2730322046244918816">"Egin atzera"</string>
-    <string name="group_system_access_home_screen" msgid="4130366993484706483">"Joan hasierako pantailara"</string>
+    <string name="group_system_access_home_screen" msgid="4130366993484706483">"Joan orri nagusira"</string>
     <string name="group_system_overview_open_apps" msgid="5659958952937994104">"Ikusi azkenaldiko aplikazioak"</string>
     <string name="group_system_cycle_forward" msgid="5478663965957647805">"Ikusi azken aplikazioak banan-banan (aurrerantz)"</string>
     <string name="group_system_cycle_back" msgid="8194102916946802902">"Ikusi azken aplikazioak banan-banan (atzerantz)"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Itzaltzeko menua"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g> orria"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Pantaila blokeatua"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ikusi zaintzeko urratsak"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ikusi zaintzeko urratsak"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Deskonektatu gailua"</string>
@@ -1085,7 +1094,7 @@
     <string name="build_number_copy_toast" msgid="877720921605503046">"Kopiatu da konpilazio-zenbakia arbelean."</string>
     <string name="basic_status" msgid="2315371112182658176">"Elkarrizketa irekia"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Elkarrizketa-widgetak"</string>
-    <string name="select_conversation_text" msgid="3376048251434956013">"Sakatu elkarrizketa bat hasierako pantailan gehitzeko"</string>
+    <string name="select_conversation_text" msgid="3376048251434956013">"Sakatu elkarrizketa bat orri nagusian gehitzeko"</string>
     <string name="no_conversations_text" msgid="5354115541282395015">"Azken elkarrizketak agertuko dira hemen"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Lehentasunezko elkarrizketak"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Azken elkarrizketak"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Oharrak idaztea"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Oharrak idaztea, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Audioa partekatzen"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Igortzen"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren audioa igortzeari utzi nahi diozu?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> aplikazioaren audioa igortzen baduzu, edo audio-irteera aldatzen baduzu, une hartako igorpena eten egingo da"</string>
diff --git a/packages/SystemUI/res/values-eu/tiles_states_strings.xml b/packages/SystemUI/res/values-eu/tiles_states_strings.xml
index d023076..accecac 100644
--- a/packages/SystemUI/res/values-eu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-eu/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Desaktibatuta"</item>
     <item msgid="578444932039713369">"Aktibatuta"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Ez dago erabilgarri"</item>
     <item msgid="8707481475312432575">"Desaktibatuta"</item>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index b3a5e36..95f17b0 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"افزودن ابزارک‌های بیشتر"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"برای سفارشی‌سازی ابزارک‌ها، فشار طولانی دهید"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"سفارشی‌سازی ابزارک‌ها"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"ویرایش ابزارک"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"برداشتن"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"افزودن ابزارک"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"زنگ زدن"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"لرزش"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"صامت"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"ارسال محتوا"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"دردسترس نیست، چون زنگ بی‌صدا شده است"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"‏%1$s. برای باصدا کردن ضربه بزنید."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"‏%1$s. برای تنظیم روی لرزش ضربه بزنید. ممکن است سرویس‌های دسترس‌پذیری بی‌صدا شوند."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏%1$s. برای صامت کردن ضربه بزنید. ممکن است سرویس‌های دسترس‌پذیری صامت شود."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‏%1$s. برای تنظیم روی لرزش، ضربه بزنید."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‏%1$s. برای صامت کردن ضربه بزنید."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"کنترل صدای محیط"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"برای تغییر حالت زنگ، ضربه بزنید"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"صامت کردن"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"باصدا کردن"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"منوی روشن/خاموش"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"صفحه <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"صفحه قفل"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"دیدن اقدامات محافظتی"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"دیدن اقدامات محافظتی"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"دستگاه را جدا کنید"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>، <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"یادداشت‌برداری"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"یادداشت‌برداری، <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"هم‌رسانی صدا"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"همه‌فرستی"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"همه‌فرستی <xliff:g id="APP_NAME">%1$s</xliff:g> متوقف شود؟"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"اگر <xliff:g id="SWITCHAPP">%1$s</xliff:g> را همه‌فرستی کنید یا خروجی را تغییر دهید، همه‌فرستی کنونی متوقف خواهد شد"</string>
diff --git a/packages/SystemUI/res/values-fa/tiles_states_strings.xml b/packages/SystemUI/res/values-fa/tiles_states_strings.xml
index b341e9e..01a549e 100644
--- a/packages/SystemUI/res/values-fa/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fa/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"خاموش"</item>
     <item msgid="578444932039713369">"روشن"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"دردسترس نیست"</item>
     <item msgid="8707481475312432575">"خاموش"</item>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 47e7f2d..ab022dd 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Lisää widgetejä"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Yksilöi widgetit pitkällä painalluksella"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Muokkaa widgettejä"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Muokkaa widgetiä"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Poista"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lisää widget"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Soittoääni"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Värinä"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Äänetön"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Striimaa"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Ei käytettävissä, soittoääni mykistetty"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Poista mykistys koskettamalla."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Siirry värinätilaan koskettamalla. Myös esteettömyyspalvelut saattavat mykistyä."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Mykistä koskettamalla. Myös esteettömyyspalvelut saattavat mykistyä."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Siirry värinätilaan napauttamalla."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Mykistä napauttamalla."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Melunvaimennus"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Vaihda soittoäänen tilaa napauttamalla"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mykistä"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"poista mykistys"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Virtavalikko"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Sivu <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Lukitusnäyttö"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Katso huoltovaiheet"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Katso huoltovaiheet"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Irrota laite"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Muistiinpanojen tekeminen"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Muistiinpanot, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Audiota jaetaan"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Lähettää"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Lopetetaanko <xliff:g id="APP_NAME">%1$s</xliff:g>-sovelluksen lähettäminen?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jos lähetät <xliff:g id="SWITCHAPP">%1$s</xliff:g>-sovellusta tai muutat ulostuloa, nykyinen lähetyksesi loppuu"</string>
diff --git a/packages/SystemUI/res/values-fi/tiles_states_strings.xml b/packages/SystemUI/res/values-fi/tiles_states_strings.xml
index bbd64fd..f7a8ec9 100644
--- a/packages/SystemUI/res/values-fi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fi/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Poissa päältä"</item>
     <item msgid="578444932039713369">"Päällä"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Ei saatavilla"</item>
     <item msgid="8707481475312432575">"Poissa päältä"</item>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 1bb8147..1186c81 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Ajouter plus de widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Maintenez le doigt pour personnaliser les widgets"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personnaliser les widgets"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Modifier le widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Retirer"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ajouter un widget"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Sonnerie"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibration"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Sonnerie désactivée"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Diffuser"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Inaccessible : sonnerie en sourdine"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Touchez pour réactiver le son."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Touchez pour activer les vibrations. Il est possible de couper le son des services d\'accessibilité."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Touchez pour couper le son. Il est possible de couper le son des services d\'accessibilité."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Touchez pour activer les vibrations."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Touchez pour couper le son."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Contrôle du bruit"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Touchez pour modifier le mode de sonnerie"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"désactiver le son"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"réactiver le son"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu de l\'interrupteur"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Écran de verrouillage"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Afficher les étapes d\'entretien"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Afficher les étapes d\'entretien"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Débranchez votre appareil"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Prise de note"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Prise de note, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Audio partagé"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Diffusion en cours…"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Arrêter la diffusion de <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si vous diffusez <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou changez la sortie, votre diffusion actuelle s\'arrêtera"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
index b969841..7b9708e 100644
--- a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Désactivé"</item>
     <item msgid="578444932039713369">"Activé"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Non disponible"</item>
     <item msgid="8707481475312432575">"Désactivé"</item>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 84160af..a02c9f7 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -385,8 +385,8 @@
     <string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Ouvrir les paramètres"</string>
     <string name="media_seamless_other_device" msgid="4654849800789196737">"Autre appareil"</string>
     <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Activer/Désactiver l\'écran Récents"</string>
-    <string name="zen_priority_introduction" msgid="3159291973383796646">"Vous ne serez dérangé par aucun son ni aucune vibration, hormis ceux des alarmes, des rappels, des événements et des appels des contacts de votre choix. Le son continuera de fonctionner notamment pour la musique, les vidéos et les jeux."</string>
-    <string name="zen_alarms_introduction" msgid="3987266042682300470">"Vous ne serez dérangé par aucun son ni aucune vibration, hormis ceux des alarmes. Le son continuera de fonctionner notamment pour la musique, les vidéos et les jeux."</string>
+    <string name="zen_priority_introduction" msgid="3159291973383796646">"Vous ne serez pas dérangé par des sons ou des vibrations, hormis ceux des alarmes, des rappels, des événements et des appelants de votre choix. Vous entendrez encore les sons que vous choisirez de jouer, notamment la musique, les vidéos et les jeux."</string>
+    <string name="zen_alarms_introduction" msgid="3987266042682300470">"Vous ne serez pas dérangé par des sons ou des vibrations, hormis ceux des alarmes. Vous entendrez encore les sons que vous choisirez de jouer, notamment la musique, les vidéos et les jeux."</string>
     <string name="zen_priority_customize_button" msgid="4119213187257195047">"Personnaliser"</string>
     <string name="zen_silence_introduction_voice" msgid="853573681302712348">"Cette option permet de bloquer TOUS les sons et les vibrations, y compris pour les alarmes, la musique, les vidéos et les jeux. Vous pourrez encore passer des appels téléphoniques."</string>
     <string name="zen_silence_introduction" msgid="6117517737057344014">"Cette option permet de bloquer TOUS les sons et les vibrations, y compris pour les alarmes, la musique, les vidéos et les jeux."</string>
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Ajouter des widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Appuyez de manière prolongée pour personnaliser les widgets"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personnaliser les widgets"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Modifier le widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Supprimer"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ajouter un widget"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Sonnerie"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibreur"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Couper le son"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Caster"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Indisponible, car la sonnerie est coupée"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Appuyez pour ne plus ignorer."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Appuyez pour mettre en mode vibreur. Vous pouvez ignorer les services d\'accessibilité."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Appuyez pour ignorer. Vous pouvez ignorer les services d\'accessibilité."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Appuyez pour mettre en mode vibreur."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Appuyez pour ignorer."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Contrôle du bruit"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Appuyez pour changer le mode de la sonnerie"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"couper le son"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"réactiver le son"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu Marche/Arrêt"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Écran de verrouillage"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Afficher les étapes d\'entretien"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Afficher les étapes d\'entretien"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Débrancher votre appareil"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Prise de notes"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Prise de notes, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Audio partagé"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Diffusion…"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Arrêter la diffusion de <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si vous diffusez <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou que vous modifiez le résultat, votre annonce actuelle s\'arrêtera"</string>
diff --git a/packages/SystemUI/res/values-fr/tiles_states_strings.xml b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
index 34440a0..af1d09d 100644
--- a/packages/SystemUI/res/values-fr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Désactivé"</item>
     <item msgid="578444932039713369">"Activé"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Indisponible"</item>
     <item msgid="8707481475312432575">"Désactivée"</item>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index b78199a..e758af8 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Engadir máis widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pulsación longa para personalizar os widgets"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Engadir widget"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Facer soar"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibrar"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Silenciar"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Emitir"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Non dispoñible (o son está silenciado)"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toca para activar o son."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toca para establecer a vibración. Pódense silenciar os servizos de accesibilidade."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca para silenciar. Pódense silenciar os servizos de accesibilidade."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toca para establecer a vibración."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toca para silenciar."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Control de ruído"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Toca para cambiar o modo de timbre"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"activar o son"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menú de acendido"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Páxina <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Pantalla de bloqueo"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver pasos de mantemento"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantemento"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Desconectar o dispositivo"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Toma de notas"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Toma de notas (<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>)"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Compartindo audio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Difusión"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Queres deixar de emitir contido a través de <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se emites contido a través de <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou cambias de saída, a emisión en curso deterase"</string>
diff --git a/packages/SystemUI/res/values-gl/tiles_states_strings.xml b/packages/SystemUI/res/values-gl/tiles_states_strings.xml
index b03f311..a963dec 100644
--- a/packages/SystemUI/res/values-gl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-gl/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Non"</item>
     <item msgid="578444932039713369">"Si"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Non dispoñible"</item>
     <item msgid="8707481475312432575">"Non"</item>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index d84b1f5..6d1d8df 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"વધુ વિજેટ ઉમેરો"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"વિજેટ કસ્ટમાઇઝ કરવા માટે થોડીવાર દબાવી રાખો"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"વિજેટ કસ્ટમાઇઝ કરો"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"વિજેટમાં ફેરફાર કરો"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"કાઢી નાખો"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"વિજેટ ઉમેરો"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"રિંગ કરો"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"વાઇબ્રેટ"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"મ્યૂટ કરો"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"કાસ્ટ કરો"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"રિંગ મ્યૂટ કરી હોવાના કારણે અનુપલબ્ધ છે"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. અનમ્યૂટ કરવા માટે ટૅપ કરો."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. વાઇબ્રેટ પર સેટ કરવા માટે ટૅપ કરો. ઍક્સેસિબિલિટી સેવાઓ મ્યૂટ કરવામાં આવી શકે છે."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. મ્યૂટ કરવા માટે ટૅપ કરો. ઍક્સેસિબિલિટી સેવાઓ મ્યૂટ કરવામાં આવી શકે છે."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. કંપન પર સેટ કરવા માટે ટૅપ કરો."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. મ્યૂટ કરવા માટે ટૅપ કરો."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"અવાજનું નિયંત્રણ"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"રિંગર મોડ બદલવા માટે ટૅપ કરો"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"મ્યૂટ કરો"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"અનમ્યૂટ કરો"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"પાવર મેનૂ"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> માંથી <xliff:g id="ID_1">%1$d</xliff:g> પૃષ્ઠ"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"લૉક સ્ક્રીન"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"સારસંભાળના પગલાં જુઓ"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"સારસંભાળના પગલાં જુઓ"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"તમારા ડિવાઇસને અનપ્લગ કરો"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"નોંધ લેવી"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"નોંધ લેવી, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"ઑડિયો શેર કરી રહ્યાં છીએ"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"બ્રૉડકાસ્ટ કરી રહ્યાં છે"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> બ્રોડકાસ્ટ કરવાનું રોકીએ?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"જો તમે <xliff:g id="SWITCHAPP">%1$s</xliff:g> બ્રોડકાસ્ટ કરો અથવા આઉટપુટ બદલો, તો તમારું હાલનું બ્રોડકાસ્ટ બંધ થઈ જશે"</string>
diff --git a/packages/SystemUI/res/values-gu/tiles_states_strings.xml b/packages/SystemUI/res/values-gu/tiles_states_strings.xml
index 5d1ad6f..580ec10 100644
--- a/packages/SystemUI/res/values-gu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-gu/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"બંધ છે"</item>
     <item msgid="578444932039713369">"ચાલુ છે"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"ઉપલબ્ધ નથી"</item>
     <item msgid="8707481475312432575">"બંધ છે"</item>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 8d1ac11..2035429 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ज़्यादा विजेट जोड़ें"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेट पसंद के मुताबिक बनाने के लिए उसे दबाकर रखें"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"विजेट अपनी पसंद के मुताबिक बनाएं"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"विजेट में बदलाव करें"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"हटाएं"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट जोड़ें"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"आवाज़ चालू है"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"वाइब्रेशन"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"आवाज़ बंद है"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"कास्ट करें"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"रिंग म्यूट होने से आवाज़ नहीं सुनाई दी"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. अनम्यूट करने के लिए टैप करें."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. कंपन पर सेट करने के लिए टैप करें. सुलभता सेवाएं म्यूट हो सकती हैं."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. म्यूट करने के लिए टैप करें. सुलभता सेवाएं म्यूट हो सकती हैं."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. कंपन (वाइब्रेशन) पर सेट करने के लिए छूएं."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. म्यूट करने के लिए टैप करें."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"शोर को कंट्रोल करने की सुविधा"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"रिंगर मोड बदलने के लिए टैप करें"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्यूट करें"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"अनम्यूट करें"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"पावर मेन्यू"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"पेज <xliff:g id="ID_2">%2$d</xliff:g> में से <xliff:g id="ID_1">%1$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"लॉक स्‍क्रीन"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"डिवाइस के रखरखाव के तरीके देखें"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"डिवाइस के रखरखाव के तरीके देखें"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"डिवाइस को अनप्लग करें"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"नोट बनाएं"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"नोट लेने के लिए, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"ऑडियो शेयर किया जा रहा है"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ब्रॉडकास्ट ऐप्लिकेशन"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर ब्रॉडकास्ट करना रोकें?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> पर ब्रॉडकास्ट शुरू करने पर या आउटपुट बदलने पर, आपका मौजूदा ब्रॉडकास्ट बंद हो जाएगा"</string>
@@ -1236,9 +1246,9 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग में जाकर, नोट लेने की सुविधा देने वाले ऐप्लिकेशन को डिफ़ॉल्ट के तौर पर सेट करें"</string>
     <string name="install_app" msgid="5066668100199613936">"ऐप्लिकेशन इंस्टॉल करें"</string>
     <string name="dismissible_keyguard_swipe" msgid="8377597870094949432">"जारी रखने के लिए, ऊपर की ओर स्वाइप करें"</string>
-    <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"क्या आपको किसी बाहरी डिवाइस पर डिसप्ले करना है?"</string>
+    <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"क्या आपको किसी बाहरी डिवाइस पर स्क्रीन शेयर करनी है?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"आपके फ़ोन के इनर डिसप्ले की स्क्रीन शेयर की जाएगी. फ़्रंट डिसप्ले को बंद कर दिया जाएगा."</string>
-    <string name="mirror_display" msgid="2515262008898122928">"डिसप्ले करें"</string>
+    <string name="mirror_display" msgid="2515262008898122928">"स्क्रीन शेयर करें"</string>
     <string name="dismiss_dialog" msgid="2195508495854675882">"खारिज करें"</string>
     <string name="connected_display_icon_desc" msgid="6373560639989971997">"डिसप्ले कनेक्ट किया गया"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"माइक्रोफ़ोन और कैमरा"</string>
diff --git a/packages/SystemUI/res/values-hi/tiles_states_strings.xml b/packages/SystemUI/res/values-hi/tiles_states_strings.xml
index cd29fb9..3fd0b30 100644
--- a/packages/SystemUI/res/values-hi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hi/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"बंद है"</item>
     <item msgid="578444932039713369">"चालू है"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"उपलब्ध नहीं है"</item>
     <item msgid="8707481475312432575">"बंद है"</item>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index d4e460d..d50a951 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodavanje još widgeta"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dugo pritisnite za prilagodbu widgeta"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prilagodi widgete"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Uredi widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Ukloni"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj widget"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Zvonjenje"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibriranje"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Zvuk je isključen"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Emitiraj"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nedostupno jer je zvono utišano"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Dodirnite da biste uključili zvuk."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Dodirnite da biste postavili na vibraciju. Usluge pristupačnosti možda neće imati zvuk."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da biste isključili zvuk. Usluge pristupačnosti možda neće imati zvuk."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dodirnite da biste postavili na vibraciju."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dodirnite da biste isključili zvuk."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Kontrola buke"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Dodirnite da biste promijenili način softvera zvona"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključivanje zvuka"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključivanje zvuka"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Izbornik tipke za uključivanje/isključivanje"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Zaključani zaslon"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Pročitajte upute za održavanje"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pročitajte upute za održavanje"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Iskopčajte uređaj"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Pisanje bilježaka"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Pisanje bilježaka, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Dijeljenje zvuka"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitiranje"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zaustaviti emitiranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ako emitirate aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g> ili promijenite izlaz, vaše će se trenutačno emitiranje zaustaviti"</string>
diff --git a/packages/SystemUI/res/values-hr/tiles_states_strings.xml b/packages/SystemUI/res/values-hr/tiles_states_strings.xml
index 32051ef..217d999 100644
--- a/packages/SystemUI/res/values-hr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hr/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Isključeno"</item>
     <item msgid="578444932039713369">"Uključeno"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Nedostupno"</item>
     <item msgid="8707481475312432575">"Isključeno"</item>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 7c62c7a..b09419b 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"További modulok hozzáadása"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nyomja meg hosszan a modulok személyre szabásához"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Modulok személyre szabása"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Modul szerkesztése"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Eltávolítás"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Modul hozzáadása"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Csörgés"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Rezgés"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Néma"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Átküldés"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nem lehetséges, a csörgés le van némítva"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Koppintson a némítás megszüntetéséhez."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Koppintson a rezgés beállításához. Előfordulhat, hogy a kisegítő lehetőségek szolgáltatásai le vannak némítva."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Koppintson a némításhoz. Előfordulhat, hogy a kisegítő lehetőségek szolgáltatásai le vannak némítva."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Koppintson a rezgés beállításához."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Koppintson a némításhoz."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Zajszabályozás"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Koppintson a csengés módjának módosításához"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"némítás"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"némítás feloldása"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Bekapcsológombhoz tartozó menü"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. oldal, összesen: <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Lezárási képernyő"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Olvassa el a kímélő használat lépéseit"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Olvassa el a kímélő használat lépéseit"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Húzza ki az eszközt"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Jegyzetelés"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Jegyzetelés, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Hang megosztása…"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Sugárzás"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Leállítja a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> közvetítését?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"A(z) <xliff:g id="SWITCHAPP">%1$s</xliff:g> közvetítése vagy a kimenet módosítása esetén a jelenlegi közvetítés leáll"</string>
diff --git a/packages/SystemUI/res/values-hu/tiles_states_strings.xml b/packages/SystemUI/res/values-hu/tiles_states_strings.xml
index 157c552..fad2cd4 100644
--- a/packages/SystemUI/res/values-hu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hu/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Ki"</item>
     <item msgid="578444932039713369">"Be"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Nem áll rendelkezésre"</item>
     <item msgid="8707481475312432575">"Ki"</item>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 8427fc3..4ea86d0 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Ավելացնել վիջեթներ"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Երկար սեղմեք՝ վիջեթները հարմարեցնելու համար"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Հարմարեցնել վիջեթները"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Փոփոխել վիջեթը"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Հեռացնել"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ավելացնել վիջեթ"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Սովորական"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Թրթռոց"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Անձայն"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Հեռարձակում"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Հասանելի չէ, երբ զանգի ձայնն անջատված է"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s: Հպեք՝ ձայնը միացնելու համար:"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s: Հպեք՝ թրթռումը միացնելու համար: Մատչելիության ծառայությունների ձայնը կարող է անջատվել:"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s: Հպեք՝ ձայնն անջատելու համար: Մատչելիության ծառայությունների ձայնը կարող է անջատվել:"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s։ Հպեք՝ թրթռոցը միացնելու համար։"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s։ Հպեք՝ ձայնը անջատելու համար։"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Աղմուկի կառավարում"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Հպեք՝ զանգակի ռեժիմը փոխելու համար"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"անջատել ձայնը"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"միացնել ձայնը"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Սնուցման կոճակի ընտրացանկ"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Էջ <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Կողպէկրան"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Քայլեր գերտաքացման ահազանգի դեպքում"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Քայլեր գերտաքացման ահազանգի դեպքում"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Անջատեք սարքը"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Նշումների ստեղծում"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Նշումների ստեղծում, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Փոխանցում է ձայնը"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Հեռարձակում"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Կանգնեցնել <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի հեռարձակումը"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Եթե հեռարձակեք <xliff:g id="SWITCHAPP">%1$s</xliff:g> հավելվածը կամ փոխեք աուդիո ելքը, ձեր ընթացիկ հեռարձակումը կկանգնեցվի։"</string>
diff --git a/packages/SystemUI/res/values-hy/tiles_states_strings.xml b/packages/SystemUI/res/values-hy/tiles_states_strings.xml
index 089716f..380d9d2 100644
--- a/packages/SystemUI/res/values-hy/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hy/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Անջատված է"</item>
     <item msgid="578444932039713369">"Միացված է"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Հասանելի չէ"</item>
     <item msgid="8707481475312432575">"Անջատված է"</item>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index a2f05b9..188f3fb 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Tambahkan widget lainnya"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tekan lama untuk menyesuaikan widget"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Sesuaikan widget"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Hapus"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tambahkan widget"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Dering"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Getar"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Nonaktifkan"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Transmisi"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Tidak tersedia karena volume dering dibisukan"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Ketuk untuk menyuarakan."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Ketuk untuk menyetel agar bergetar. Layanan aksesibilitas mungkin dibisukan."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ketuk untuk membisukan. Layanan aksesibilitas mungkin dibisukan."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Ketuk untuk menyetel agar bergetar."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ketuk untuk menonaktifkan."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Kontrol Bising"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Ketuk untuk mengubah mode pendering"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"Tanpa suara"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktifkan"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu daya"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> dari <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Layar kunci"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Lihat langkah-langkah perawatan"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Lihat langkah-langkah perawatan"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Cabut perangkat"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Pembuatan catatan"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Pembuatan catatan, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Berbagi audio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Menyiarkan"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hentikan siaran <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jika Anda menyiarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g> atau mengubah output, siaran saat ini akan dihentikan"</string>
diff --git a/packages/SystemUI/res/values-in/tiles_states_strings.xml b/packages/SystemUI/res/values-in/tiles_states_strings.xml
index 71460a71..9be5d02 100644
--- a/packages/SystemUI/res/values-in/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-in/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Nonaktif"</item>
     <item msgid="578444932039713369">"Aktif"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Tidak tersedia"</item>
     <item msgid="8707481475312432575">"Nonaktif"</item>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 9c9a29f..47756c2 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Bæta við fleiri græjum"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Haltu inni til að sérsníða græjur"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Sérsníða græjur"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Breyta græju"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Fjarlægja"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Bæta græju við"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Hringing"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Titringur"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Hljóð af"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Senda út"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Ekki í boði þar sem hringing er þögguð"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Ýttu til að hætta að þagga."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Ýttu til að stilla á titring. Hugsanlega verður slökkt á hljóði aðgengisþjónustu."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ýttu til að þagga. Hugsanlega verður slökkt á hljóði aðgengisþjónustu."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Ýttu til að stilla á titring."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ýttu til að þagga."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Hávaðavörn"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Ýta til að skipta um hringjarastillingu"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"þagga"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"hætta að þagga"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Aflrofavalmynd"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Blaðsíða <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Lásskjár"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Sjá varúðarskref"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Sjá varúðarskref"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Taktu tækið úr sambandi"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Glósugerð"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Glósugerð, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Deilir hljóði"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Útsending í gangi"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hætta að senda út <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ef þú sendir út <xliff:g id="SWITCHAPP">%1$s</xliff:g> eða skiptir um úttak lýkur yfirstandandi útsendingu"</string>
diff --git a/packages/SystemUI/res/values-is/tiles_states_strings.xml b/packages/SystemUI/res/values-is/tiles_states_strings.xml
index 17aaf6c..1ee6e47 100644
--- a/packages/SystemUI/res/values-is/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-is/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Slökkt"</item>
     <item msgid="578444932039713369">"Kveikt"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Ekki í boði"</item>
     <item msgid="8707481475312432575">"Slökkt"</item>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index ec58af8..5bad44c 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -99,7 +99,7 @@
     <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> e altre app aperte hanno rilevato questo screenshot."</string>
     <string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Aggiungi alla nota"</string>
     <string name="screenrecord_title" msgid="4257171601439507792">"Registrazione dello schermo"</string>
-    <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Elaboraz. registraz. schermo"</string>
+    <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Elaborazione registrazione…"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notifica costante per una sessione di registrazione dello schermo"</string>
     <string name="screenrecord_permission_dialog_title" msgid="303380743267672953">"Iniziare a registrare?"</string>
     <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="4152602778470789965">"Quando registri, 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>
@@ -111,7 +111,7 @@
     <string name="screenrecord_mic_label" msgid="2111264835791332350">"Microfono"</string>
     <string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"Audio del dispositivo e microfono"</string>
     <string name="screenrecord_continue" msgid="4055347133700593164">"Inizia"</string>
-    <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"Registrazione schermo"</string>
+    <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"Registrazione schermo in corso…"</string>
     <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"Registrazione schermo e audio"</string>
     <string name="screenrecord_taps_label" msgid="1595690528298857649">"Mostra tocchi sullo schermo"</string>
     <string name="screenrecord_stop_label" msgid="72699670052087989">"Interrompi"</string>
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Aggiungi altri widget"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Premi a lungo per personalizzare i widget"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizza widget"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Modifica widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Rimuovi"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Aggiungi widget"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Attiva suoneria"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Attiva vibrazione"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Silenzia"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Trasmissione"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Non disponibile con l\'audio disattivato"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tocca per riattivare l\'audio."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tocca per attivare la vibrazione. L\'audio dei servizi di accessibilità può essere disattivato."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tocca per disattivare l\'audio. L\'audio dei servizi di accessibilità può essere disattivato."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tocca per attivare la vibrazione."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tocca per disattivare l\'audio."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Controllo del rumore"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Tocca per cambiare la modalità della suoneria"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenzia"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"riattiva l\'audio"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu del tasto di accensione"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> di <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Schermata di blocco"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Leggi le misure da adottare"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Leggi le misure da adottare"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Scollega il dispositivo"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Aggiunta di note"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Aggiunta di note, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Condivisione di audio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Trasmissione in corso…"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vuoi interrompere la trasmissione dell\'app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se trasmetti l\'app <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambi l\'uscita, la trasmissione attuale viene interrotta"</string>
diff --git a/packages/SystemUI/res/values-it/tiles_states_strings.xml b/packages/SystemUI/res/values-it/tiles_states_strings.xml
index 7aa09d4..28e28ae 100644
--- a/packages/SystemUI/res/values-it/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-it/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Off"</item>
     <item msgid="578444932039713369">"On"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Non disponibile"</item>
     <item msgid="8707481475312432575">"Off"</item>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index c9a71c7..154de15 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"הוספת ווידג\'טים"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"לוחצים לחיצה ארוכה כדי להתאים אישית את הווידג\'טים"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"התאמה אישית של ווידג\'טים"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"עריכת הווידג\'ט"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"הסרה"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"הוספת ווידג\'ט"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"צלצול"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"רטט"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"השתקה"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"‏הפעלת Cast"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"לא זמין כי הצלצול מושתק"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"‏%1$s. יש להקיש כדי לבטל את ההשתקה."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"‏%1$s. צריך להקיש כדי להגדיר רטט. ייתכן ששירותי הנגישות מושתקים."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏%1$s. יש להקיש כדי להשתיק. ייתכן ששירותי הנגישות יושתקו."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‏%1$s. יש להקיש כדי להעביר למצב רטט."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‏%1$s. יש להקיש כדי להשתיק."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"בקרת הרעש"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"יש להקיש כדי לשנות את מצב תוכנת הצלצול"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"השתקה"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ביטול ההשתקה"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"תפריט הפעלה"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"דף <xliff:g id="ID_1">%1$d</xliff:g> מתוך <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"מסך נעילה"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"לצפייה בשלבי הטיפול"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"לצפייה בשלבי הטיפול"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"ניתוק המכשיר"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"כתיבת הערות"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"כתיבת הערות, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"שיתוף האודיו"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"שידור"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"האם להפסיק לשדר את התוכן מאפליקציית <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"אם משדרים את התוכן מאפליקציית <xliff:g id="SWITCHAPP">%1$s</xliff:g> או משנים את הפלט, השידור הנוכחי יפסיק לפעול"</string>
diff --git a/packages/SystemUI/res/values-iw/tiles_states_strings.xml b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
index bd2a6f7..bb3eb10 100644
--- a/packages/SystemUI/res/values-iw/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"כבוי"</item>
     <item msgid="578444932039713369">"פועל"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"לא זמין"</item>
     <item msgid="8707481475312432575">"כבוי"</item>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index dc33b0d..227edd3 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -429,6 +429,7 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ウィジェットの追加"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長押ししてウィジェットをカスタマイズ"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ウィジェットのカスタマイズ"</string>
+    <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"無効なウィジェットのアプリアイコン"</string>
     <string name="edit_widget" msgid="9030848101135393954">"ウィジェットを編集"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"削除"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ウィジェットを追加"</string>
@@ -573,11 +574,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"着信音"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"バイブレーション"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"ミュート"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"キャスト"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"着信音がミュートされているため利用できません"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s。タップしてミュートを解除します。"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s。タップしてバイブレーションに設定します。ユーザー補助機能サービスがミュートされる場合があります。"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。タップしてミュートします。ユーザー補助機能サービスがミュートされる場合があります。"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。タップしてバイブレーションに設定します。"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。タップしてミュートします。"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"ノイズ コントロール"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"タップすると、着信音のモードを変更できます"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ミュート"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ミュートを解除"</string>
@@ -832,6 +836,8 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"電源ボタン メニュー"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"ページ <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"ロック画面"</string>
+    <string name="finder_active" msgid="7907846989716941952">"「デバイスを探す」を使うと、電源が OFF の状態でもこのスマートフォンの現在地を確認できます"</string>
+    <string name="shutdown_progress" msgid="5464239146561542178">"シャットダウン中…"</string>
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"取り扱いに関する手順をご覧ください"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"取り扱いに関する手順をご覧ください"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"デバイスを電源から外します"</string>
@@ -1186,6 +1192,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>、<xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"メモ"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"メモ、<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"音声を共有中"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ブロードキャスト"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> のブロードキャストを停止しますか?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> をブロードキャストしたり、出力を変更したりすると、現在のブロードキャストが停止します。"</string>
diff --git a/packages/SystemUI/res/values-ja/tiles_states_strings.xml b/packages/SystemUI/res/values-ja/tiles_states_strings.xml
index 31158ca..ebadf3b 100644
--- a/packages/SystemUI/res/values-ja/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ja/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"OFF"</item>
     <item msgid="578444932039713369">"ON"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"使用不可"</item>
     <item msgid="8707481475312432575">"OFF"</item>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index d78bc20..70eeb33 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ვიჯეტების დამატება"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ხანგრძლივად დააჭირეთ ვიჯეტების მოსარგებად"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ვიჯეტების მორგება"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"ვიჯეტის რედაქტირება"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"ამოშლა"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ვიჯეტის დამატება"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"დარეკვა"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"ვიბრაცია"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"დადუმება"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"ტრანსლირება"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"ზარის დადუმების გამო ხელმისაწვდომი არაა"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. შეეხეთ დადუმების გასაუქმებლად."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. შეეხეთ ვიბრაციაზე დასაყენებლად. შეიძლება დადუმდეს მარტივი წვდომის სერვისებიც."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. შეეხეთ დასადუმებლად. შეიძლება დადუმდეს მარტივი წვდომის სერვისებიც."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. შეეხეთ ვიბრაციაზე დასაყენებლად."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. შეეხეთ დასადუმებლად."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"ხმაურის კონტროლი"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"შეეხეთ მრეკავის რეჟიმის შესაცვლელად"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"დადუმება"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"დადუმების მოხსნა"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ჩართვის მენიუ"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"გვერდი <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>-დან"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"ჩაკეტილი ეკრანი"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"მისაღები ზომების გაცნობა"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"მისაღები ზომების გაცნობა"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"გამოაერᲗეᲗ Თქვენი მოწყობილობა"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"ჩანიშვნა"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"ჩანიშვნა, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"აუდიოს გაზიარება"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"იწყებთ მაუწყებლობას"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"გსურთ <xliff:g id="APP_NAME">%1$s</xliff:g>-ის ტრანსლაციის შეჩერება?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g>-ის ტრანსლაციის შემთხვევაში ან აუდიოს გამოსასვლელის შეცვლისას, მიმდინარე ტრანსლაცია შეჩერდება"</string>
diff --git a/packages/SystemUI/res/values-ka/tiles_states_strings.xml b/packages/SystemUI/res/values-ka/tiles_states_strings.xml
index 366030a..07a8a76 100644
--- a/packages/SystemUI/res/values-ka/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ka/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"გამორთულია"</item>
     <item msgid="578444932039713369">"ჩართულია"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"მიუწვდომელია"</item>
     <item msgid="8707481475312432575">"გამორთულია"</item>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 407da0b..c2525d9 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Басқа виджеттер қосыңыз."</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджеттерді бейімдеу үшін ұзақ басып тұрыңыз."</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Виджеттерді реттеу"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Виджетті өзгерту"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Өшіру"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет қосу"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Шылдырлау"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Діріл"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Дыбысын өшіру"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Трансляциялау"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Қолжетімді емес, шылдырлату өшірулі."</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Дыбысын қосу үшін түртіңіз."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Діріл режимін орнату үшін түртіңіз. Арнайы мүмкіндік қызметтерінің дыбысы өшуі мүмкін."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Дыбысын өшіру үшін түртіңіз. Арнайы мүмкіндік қызметтерінің дыбысы өшуі мүмкін."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Діріл режимін орнату үшін түртіңіз."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Дыбысын өшіру үшін түртіңіз."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Шуды реттеу"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Қоңырау режимін өзгерту үшін түртіңіз."</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"дыбысын өшіру"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"дыбысын қосу"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Қуат мәзірі"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> ішінен <xliff:g id="ID_1">%1$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Құлыптаулы экран"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Пайдалану нұсқаулығын қараңыз"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Пайдалану нұсқаулығын қараңыз"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Құрылғыны ажыратыңыз"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Ескертпе жазу"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Ескертпе жазу, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Аудио бөлісу"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Таратуда"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын таратуды тоқтатасыз ба?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> қолданбасын таратсаңыз немесе аудио шығысын өзгертсеңіз, қазіргі тарату сеансы тоқтайды."</string>
diff --git a/packages/SystemUI/res/values-kk/tiles_states_strings.xml b/packages/SystemUI/res/values-kk/tiles_states_strings.xml
index b8089e4..f5b0948 100644
--- a/packages/SystemUI/res/values-kk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-kk/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Өшірулі"</item>
     <item msgid="578444932039713369">"Қосулы"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Қолжетімсіз"</item>
     <item msgid="8707481475312432575">"Өшірулі"</item>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index eaca657..0d25033 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"បញ្ចូលធាតុ​ក្រាហ្វិកច្រើនទៀត"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ចុច​ឱ្យ​យូរ ដើម្បីប្ដូរធាតុ​ក្រាហ្វិកតាមបំណង"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ប្ដូរ​ធាតុ​ក្រាហ្វិកតាម​បំណង"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"កែធាតុ​ក្រាហ្វិក"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"ដកចេញ"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"បញ្ចូលធាតុ​ក្រាហ្វិក"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"រោទ៍"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"ញ័រ"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"បិទសំឡេង"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"បញ្ជូន"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"មិន​អាច​ប្រើ​បាន​ទេ​ ព្រោះ​សំឡេង​រោទ៍​ត្រូវ​បាន​បិទ"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s។ ប៉ះដើម្បីបើកសំឡេង។"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s។ ប៉ះដើម្បីកំណត់ឲ្យញ័រ។ សេវាកម្មលទ្ធភាពប្រើប្រាស់អាចនឹងត្រូវបានបិទសំឡេង។"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s។ ប៉ះដើម្បីបិទសំឡេង។ សេវាកម្មលទ្ធភាពប្រើប្រាស់អាចនឹងត្រូវបានបិទសំឡេង។"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s ។ ចុច​ដើម្បី​កំណត់​ឲ្យ​ញ័រ។"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s ។ ចុច​ដើម្បី​បិទ​សំឡេង។"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"ការគ្រប់គ្រង​សំឡេងរំខាន"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"ចុច​ដើម្បីប្ដូរ​មុខងារ​រោទ៍"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"បិទ​សំឡេង"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"បើក​សំឡេង"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ម៉ឺនុយ​ថាមពល"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"ទំព័រ <xliff:g id="ID_1">%1$d</xliff:g> នៃ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"អេក្រង់​ចាក់សោ"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"មើលជំហាន​ថែទាំ"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"មើលជំហាន​ថែទាំ"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"ដកឧបករណ៍របស់អ្នក"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"ការកត់ត្រា"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"ការកត់ត្រា, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"កំពុងចែករំលែកសំឡេង"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ការផ្សាយ"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"បញ្ឈប់ការផ្សាយ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ប្រសិនបើអ្នក​ផ្សាយ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ឬប្ដូរឧបករណ៍បញ្ចេញសំឡេង ការផ្សាយបច្ចុប្បន្នរបស់អ្នកនឹង​បញ្ឈប់"</string>
diff --git a/packages/SystemUI/res/values-km/tiles_states_strings.xml b/packages/SystemUI/res/values-km/tiles_states_strings.xml
index 8c5c8d1..a2031b0 100644
--- a/packages/SystemUI/res/values-km/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-km/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"បិទ"</item>
     <item msgid="578444932039713369">"បើក"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"មិនមានទេ"</item>
     <item msgid="8707481475312432575">"បិទ"</item>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 64179ba..66b8e72 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ಹೆಚ್ಚಿನ ವಿಜೆಟ್‌ಗಳನ್ನು ಸೇರಿಸಿ"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ವಿಜೆಟ್‌ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಲು ದೀರ್ಘಕಾಲ ಒತ್ತಿರಿ"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ವಿಜೆಟ್‌ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"ವಿಜೆಟ್ ಅನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"ತೆಗೆದುಹಾಕಿ"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ವಿಜೆಟ್ ಅನ್ನು ಸೇರಿಸಿ"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"ರಿಂಗ್"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"ವೈಬ್ರೇಟ್‌"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"ಮ್ಯೂಟ್"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"ಬಿತ್ತರಿಸಿ"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"ರಿಂಗ್ ಮ್ಯೂಟ್ ಆಗಿರುವ ಕಾರಣ ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ಅನ್‌ಮ್ಯೂಟ್‌ ಮಾಡುವುದಕ್ಕಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. ಕಂಪನಕ್ಕೆ ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ ಸೇವೆಗಳನ್ನು ಮ್ಯೂಟ್‌ ಮಾಡಬಹುದು."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ಮ್ಯೂಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ ಸೇವೆಗಳನ್ನು ಮ್ಯೂಟ್‌ ಮಾಡಬಹುದು."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. ವೈಬ್ರೇಟ್ ಮಾಡಲು ಹೊಂದಿಸುವುದಕ್ಕಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. ಮ್ಯೂಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"ಗದ್ದಲ ನಿಯಂತ್ರಣ"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"ರಿಂಗರ್ ಮೋಡ್ ಬದಲಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ಮ್ಯೂಟ್ ಮಾಡಿ"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ಅನ್‌ಮ್ಯೂಟ್ ಮಾಡಿ"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ಪವರ್ ಮೆನು"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="ID_1">%1$d</xliff:g> ಪುಟ"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"ಲಾಕ್ ಪರದೆ"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ಕಾಳಜಿಯ ಹಂತಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ಕಾಳಜಿಯ ಹಂತಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್‌ಪ್ಲಗ್ ಮಾಡಿ"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"ಟಿಪ್ಪಣಿ ಮಾಡಿಕೊಳ್ಳುವಿಕೆ"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"ಟಿಪ್ಪಣಿ ಮಾಡಿಕೊಳ್ಳುವಿಕೆ, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"ಆಡಿಯೊವನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ಪ್ರಸಾರ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ನ ಪ್ರಸಾರವನ್ನು ನಿಲ್ಲಿಸಬೇಕೆ?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ನೀವು <xliff:g id="SWITCHAPP">%1$s</xliff:g> ಅನ್ನು ಪ್ರಸಾರ ಮಾಡಿದರೆ ಅಥವಾ ಔಟ್‌ಪುಟ್ ಅನ್ನು ಬದಲಾಯಿಸಿದರೆ, ನಿಮ್ಮ ಪ್ರಸ್ತುತ ಪ್ರಸಾರವು ಸ್ಥಗಿತಗೊಳ್ಳುತ್ತದೆ"</string>
diff --git a/packages/SystemUI/res/values-kn/tiles_states_strings.xml b/packages/SystemUI/res/values-kn/tiles_states_strings.xml
index 250eb5a..de0fcae 100644
--- a/packages/SystemUI/res/values-kn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-kn/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"ಆಫ್"</item>
     <item msgid="578444932039713369">"ಆನ್"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"ಲಭ್ಯವಿಲ್ಲ"</item>
     <item msgid="8707481475312432575">"ಆಫ್"</item>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 26825e0..028c8cf 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"더 많은 위젯 추가"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"위젯을 맞춤설정하려면 길게 누르기"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"위젯 맞춤설정"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"위젯 수정"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"삭제"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"위젯 추가"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"벨소리"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"진동"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"음소거"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"전송"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"벨소리가 음소거되어 있으므로 사용할 수 없음"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. 탭하여 음소거를 해제하세요."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. 탭하여 진동으로 설정하세요. 접근성 서비스가 음소거될 수 있습니다."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. 탭하여 음소거로 설정하세요. 접근성 서비스가 음소거될 수 있습니다."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. 탭하여 진동으로 설정하세요."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. 탭하여 음소거로 설정하세요."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"소음 제어"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"탭하여 벨소리 장치 모드 변경"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"음소거"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"음소거 해제"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"전원 메뉴"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>페이지 중 <xliff:g id="ID_1">%1$d</xliff:g>페이지"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"잠금 화면"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"해결 방법 확인하기"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"해결 방법 확인하기"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"기기 분리하기"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"메모"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"메모, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"오디오 공유 중"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"방송 중"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> 방송을 중지하시겠습니까?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> 앱을 방송하거나 출력을 변경하면 기존 방송이 중단됩니다"</string>
diff --git a/packages/SystemUI/res/values-ko/tiles_states_strings.xml b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
index 7981d28..c9b2846 100644
--- a/packages/SystemUI/res/values-ko/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"꺼짐"</item>
     <item msgid="578444932039713369">"켜짐"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"이용 불가"</item>
     <item msgid="8707481475312432575">"꺼짐"</item>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 7954686..0f00555 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Көбүрөөк виджеттерди кошуу"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджеттерди ыңгайлаштыруу үчүн кое бербей басып туруңуз"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Виджеттерди ыңгайлаштыруу"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Виджетти түзөтүү"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Өчүрүү"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет кошуу"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Шыңгыратуу"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Дирилдөө"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Үнсүз"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Тышкы экранга чыгруу"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Үнсүз режимде жеткиликсиз"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Үнүн чыгаруу үчүн таптап коюңуз."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Дирилдөөгө коюу үчүн таптап коюңуз. Атайын мүмкүнчүлүктөр кызматынын үнүн өчүрүп койсо болот."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Үнүн өчүрүү үчүн таптап коюңуз. Атайын мүмкүнчүлүктөр кызматынын үнүн өчүрүп койсо болот."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Дирилдөөгө коюу үчүн басыңыз."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Үнүн өчүрүү үчүн басыңыз."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Ызы-чууну көзөмөлдөө"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Коңгуроо режимин өзгөртүү үчүн басыңыз"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"үнсүз"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"үнүн чыгаруу"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Кубат баскычынын менюсу"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> ичинен <xliff:g id="ID_1">%1$d</xliff:g>-бет"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Кулпуланган экран"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Тейлөө кадамдарын көрүңүз"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Тейлөө кадамдарын көрүңүз"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Түзмөктү сууруп коюңуз"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Эскертме жазуу"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Эскертме жазуу (<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>)"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Аудиону бөлүшүү"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Кеңири таратуу"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда кабарлоо токтотулсунбу?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Эгер <xliff:g id="SWITCHAPP">%1$s</xliff:g> колдонмосунда кабарласаңыз же аудионун чыгуусун өзгөртсөңүз, учурдагы кабарлоо токтотулат"</string>
diff --git a/packages/SystemUI/res/values-ky/tiles_states_strings.xml b/packages/SystemUI/res/values-ky/tiles_states_strings.xml
index 0f277f9..bc47e5a 100644
--- a/packages/SystemUI/res/values-ky/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ky/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Өчүк"</item>
     <item msgid="578444932039713369">"Күйүк"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Жеткиликсиз"</item>
     <item msgid="8707481475312432575">"Өчүк"</item>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 4c1bd4e..db97655 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -429,6 +429,7 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ເພີ່ມວິດເຈັດເພີ່ມເຕີມ"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ກົດຄ້າງໄວ້ເພື່ອປັບແຕ່ງວິດເຈັດ"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ປັບແຕ່ງວິດເຈັດ"</string>
+    <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ໄອຄອນແອັບສຳລັບວິດເຈັດທີ່ຖືກປິດການນຳໃຊ້"</string>
     <string name="edit_widget" msgid="9030848101135393954">"ແກ້ໄຂວິດເຈັດ"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"ລຶບອອກ"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ເພີ່ມວິດເຈັດ"</string>
@@ -573,11 +574,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"​ເຕືອນ​ດ້ວຍ​ສຽງ"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"ສັ່ນເຕືອນ"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"ປິດ"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"ສົ່ງສັນຍານ"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"ບໍ່ມີໃຫ້ໃຊ້ເນື່ອງຈາກມີການປິດສຽງໂທເຂົ້າ"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ແຕະເພື່ອເຊົາປິດສຽງ."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. ແຕະເພື່ອຕັ້ງເປັນສັ່ນ. ບໍລິການຊ່ວຍເຂົ້າເຖິງອາດຖືກປິດສຽງໄວ້."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ແຕະເພື່ອປິດສຽງ. ບໍລິການຊ່ວຍເຂົ້າເຖິງອາດຖືກປິດສຽງໄວ້."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. ແຕະເພື່ອຕັ້ງເປັນສັ່ນເຕືອນ."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. ແຕະເພື່ອປິດສຽງ."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"ການຄວບຄຸມສຽງລົບກວນ"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"ແຕະເພື່ອປ່ຽນໂໝດຣິງເກີ"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ປິດສຽງ"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ເຊົາປິດສຽງ"</string>
@@ -832,6 +836,8 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ເມນູເປີດປິດ"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g> ຈາກທັງໝົດ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"ໜ້າຈໍລັອກ"</string>
+    <string name="finder_active" msgid="7907846989716941952">"ທ່ານສາມາດຊອກຫາສະຖານທີ່ຂອງໂທລະສັບເຄື່ອງນີ້ໄດ້ດ້ວຍແອັບຊອກຫາອຸປະກອນຂອງຂ້ອຍເຖິງແມ່ນວ່າຈະປິດເຄື່ອງຢູ່ກໍຕາມ"</string>
+    <string name="shutdown_progress" msgid="5464239146561542178">"ກຳລັງປິດເຄື່ອງ…"</string>
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ເບິ່ງຂັ້ນຕອນການເບິ່ງແຍງ"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ເບິ່ງຂັ້ນຕອນການເບິ່ງແຍງ"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"ຖອດອຸປະກອນຂອງທ່ານອອກ"</string>
@@ -1186,6 +1192,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"ການຈົດບັນທຶກ"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"ການຈົດບັນທຶກ <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"ກຳລັງແບ່ງປັນສຽງ"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ກຳລັງອອກອາກາດ"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"ຢຸດການອອກອາກາດ <xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ຫາກທ່ານອອກອາກາດ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ຫຼື ປ່ຽນເອົ້າພຸດ, ການອອກອາກາດປັດຈຸບັນຂອງທ່ານຈະຢຸດ"</string>
diff --git a/packages/SystemUI/res/values-lo/tiles_states_strings.xml b/packages/SystemUI/res/values-lo/tiles_states_strings.xml
index d54cf4d..7595897 100644
--- a/packages/SystemUI/res/values-lo/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lo/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"ປິດ"</item>
     <item msgid="578444932039713369">"ເປີດ"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"ບໍ່ສາມາດໃຊ້ໄດ້"</item>
     <item msgid="8707481475312432575">"ປິດ"</item>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 9a261e0..9eaab8f 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Pridėkite daugiau valdiklių"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Ilgai paspauskite, kad tinkintumėte valdiklius"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Tinkinti valdiklius"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Redaguoti valdiklį"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Pašalinti"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pridėti valdiklį"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Skambinti"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibruoti"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Nutildyti"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Perdavimas"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nepasiekiama, nes skambutis nutildytas"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Palieskite, kad įjungtumėte garsą."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Palieskite, kad nustatytumėte vibravimą. Gali būti nutildytos pritaikymo neįgaliesiems paslaugos."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Palieskite, kad nutildytumėte. Gali būti nutildytos pritaikymo neįgaliesiems paslaugos."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Palieskite, kad nustatytumėte vibravimą."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Palieskite, kad nutildytumėte."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Triukšmo valdymas"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Palieskite, kad pakeistumėte skambučio režimą"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"nutildyti"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"įjungti garsą"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Įjungimo meniu"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g> psl. iš <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Užrakinimo ekranas"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Žr. priežiūros veiksmus"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Žr. priežiūros veiksmus"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Atjunkite įrenginį"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Užrašų kūrimas"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Užrašų kūrimas, „<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>“"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Bendrinamas garsas"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transliavimas"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Sustabdyti „<xliff:g id="APP_NAME">%1$s</xliff:g>“ transliaciją?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jei transliuosite „<xliff:g id="SWITCHAPP">%1$s</xliff:g>“ arba pakeisite išvestį, dabartinė transliacija bus sustabdyta"</string>
diff --git a/packages/SystemUI/res/values-lt/tiles_states_strings.xml b/packages/SystemUI/res/values-lt/tiles_states_strings.xml
index e66f590..94343ba 100644
--- a/packages/SystemUI/res/values-lt/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lt/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Išjungta"</item>
     <item msgid="578444932039713369">"Įjungta"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Nepasiekiama"</item>
     <item msgid="8707481475312432575">"Išjungta"</item>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index a9a1a3c..f69afb9 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Pievienot citus logrīkus"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nospiediet un turiet, lai pielāgotu logrīkus."</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Pielāgot logrīkus"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Rediģēt logrīku"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Noņemt"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pievienot logrīku"</string>
@@ -573,11 +575,16 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Zvanīt"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibrēt"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Izslēgt skaņu"</string>
+    <!-- no translation found for media_device_cast (4786241789687569892) -->
+    <skip />
+    <!-- no translation found for stream_notification_unavailable (4313854556205836435) -->
+    <skip />
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Pieskarieties, lai ieslēgtu skaņu."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Pieskarieties, lai iestatītu uz vibrozvanu. Var tikt izslēgti pieejamības pakalpojumu signāli."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Pieskarieties, lai izslēgtu skaņu. Var tikt izslēgti pieejamības pakalpojumu signāli."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Pieskarieties, lai iestatītu vibrozvanu."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Pieskarieties, lai izslēgtu skaņu."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Trokšņu kontrole"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Pieskarieties, lai mainītu zvanītāja režīmu."</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"izslēgt skaņu"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ieslēgt skaņu"</string>
@@ -832,6 +839,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Barošanas izvēlne"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. lpp. no <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Bloķēšanas ekrāns"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Skatīt apkopes norādījumus"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Skatīt apkopes norādījumus"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Atvienojiet savu ierīci"</string>
@@ -1186,6 +1197,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Piezīmju pierakstīšana"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Piezīmju pierakstīšana, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Notiek audio kopīgošana"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Notiek apraidīšana"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vai apturēt lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> apraidīšanu?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ja sāksiet lietotnes <xliff:g id="SWITCHAPP">%1$s</xliff:g> apraidīšanu vai mainīsiet izvadi, pašreizējā apraide tiks apturēta"</string>
diff --git a/packages/SystemUI/res/values-lv/tiles_states_strings.xml b/packages/SystemUI/res/values-lv/tiles_states_strings.xml
index d32efec..d8b2467 100644
--- a/packages/SystemUI/res/values-lv/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lv/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Izslēgta"</item>
     <item msgid="578444932039713369">"Ieslēgta"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Nav pieejama"</item>
     <item msgid="8707481475312432575">"Izslēgta"</item>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 20a93f7..6ea4d1f 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Додајте повеќе виџети"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Притиснете долго за да ги приспособите виџетите"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Приспособете ги виџетите"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Изменување виџети"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Отстранува"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додајте виџет"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Ѕвони"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Вибрации"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Исклучи звук"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Емитување"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Недостапно бидејќи ѕвонењето е исклучено"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Допрете за да вклучите звук."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Допрете за да поставите на вибрации. Можеби ќе се исклучи звукот на услугите за достапност."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Допрете за да исклучите звук. Можеби ќе се исклучи звукот на услугите за достапност."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Допрете за да се постави на вибрации."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Допрете за да се исклучи звукот."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Контрола на бучавата"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Допрете за да го промените режимот на ѕвончето"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"исклучен звук"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"вклучен звук"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Мени на копчето за вклучување"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Страница <xliff:g id="ID_1">%1$d</xliff:g> од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Заклучен екран"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Прикажи ги чекорите за грижа за уредот"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Прикажи ги чекорите за грижа за уредот"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Исклучете го уредот од кабел"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Фаќање белешки"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Фаќање белешки, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Се споделува аудио"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Емитување"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Да се прекине емитувањето на <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ако емитувате на <xliff:g id="SWITCHAPP">%1$s</xliff:g> или го промените излезот, тековното емитување ќе запре"</string>
diff --git a/packages/SystemUI/res/values-mk/tiles_states_strings.xml b/packages/SystemUI/res/values-mk/tiles_states_strings.xml
index 0a42d7c..8b0faf7 100644
--- a/packages/SystemUI/res/values-mk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mk/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Исклучено"</item>
     <item msgid="578444932039713369">"Вклучено"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Недостапно"</item>
     <item msgid="8707481475312432575">"Исклучено"</item>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index fc2bc47..82d257a 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -429,6 +429,7 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"കൂടുതൽ വിജറ്റുകൾ ചേർക്കുക"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"വിജറ്റുകൾ ഇഷ്ടാനുസൃതമാക്കാൻ ദീർഘനേരം അമർത്തുക"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"വിജറ്റുകൾ ഇഷ്ടാനുസൃതമാക്കുക"</string>
+    <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"പ്രവർത്തനരഹിതമാക്കിയ വിജറ്റിനുള്ള ആപ്പ് ഐക്കൺ"</string>
     <string name="edit_widget" msgid="9030848101135393954">"വിജറ്റ് എഡിറ്റ് ചെയ്യുക"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"നീക്കം ചെയ്യുക"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"വിജറ്റ് ചേർക്കുക"</string>
@@ -573,11 +574,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"റിംഗ് ചെയ്യുക"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"വൈബ്രേറ്റ് ചെയ്യുക"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"മ്യൂട്ട് ചെയ്യുക"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"കാസ്റ്റ് ചെയ്യുക"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"റിംഗ് മ്യൂട്ട് ചെയ്തതിനാൽ ലഭ്യമല്ല"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. അൺമ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. വൈബ്രേറ്റിലേക്ക് സജ്ജമാക്കുന്നതിന് ടാപ്പുചെയ്യുക. ഉപയോഗസഹായി സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. മ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക. ഉപയോഗസഹായി സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s വൈബ്രേറ്റിലേക്ക് സജ്ജമാക്കുന്നതിന് ടാപ്പുചെയ്യുക."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s മ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"നോയ്‌സ് നിയന്ത്രണം"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"റിംഗർ മോഡ് മാറ്റാൻ ടാപ്പ് ചെയ്യുക"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"മ്യൂട്ട് ചെയ്യുക"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"അൺമ്യൂട്ട് ചെയ്യുക"</string>
@@ -832,6 +836,8 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"പവർ മെനു"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"പേജ് <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"ലോക്ക് സ്‌ക്രീൻ"</string>
+    <string name="finder_active" msgid="7907846989716941952">"ഓഫായിരിക്കുമ്പോഴും Find My Device ഉപയോഗിച്ച് നിങ്ങൾക്ക് ഈ ഫോൺ കണ്ടെത്താനാകും"</string>
+    <string name="shutdown_progress" msgid="5464239146561542178">"ഷട്ട്‌ഡൗൺ ചെയ്യുന്നു…"</string>
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"പരിപാലന നിർദ്ദേശങ്ങൾ കാണുക"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"പരിപാലന നിർദ്ദേശങ്ങൾ കാണുക"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"ഉപകരണം അൺപ്ലഗ് ചെയ്യുക"</string>
@@ -1186,6 +1192,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"കുറിപ്പ് രേഖപ്പെടുത്തൽ"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"കുറിപ്പ് രേഖപ്പെടുത്തൽ, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"ഓഡിയോ പങ്കിടുന്നു"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"പ്രക്ഷേപണം ചെയ്യുന്നു"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ബ്രോഡ്‌കാസ്റ്റ് ചെയ്യുന്നത് അവസാനിപ്പിക്കണോ?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"നിങ്ങൾ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ബ്രോഡ്‌കാസ്റ്റ് ചെയ്യുകയോ ഔട്ട്പുട്ട് മാറ്റുകയോ ചെയ്താൽ നിങ്ങളുടെ നിലവിലുള്ള ബ്രോഡ്‌കാസ്റ്റ് അവസാനിക്കും"</string>
diff --git a/packages/SystemUI/res/values-ml/tiles_states_strings.xml b/packages/SystemUI/res/values-ml/tiles_states_strings.xml
index 62bac5c..529d0de 100644
--- a/packages/SystemUI/res/values-ml/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ml/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"ഓഫാണ്"</item>
     <item msgid="578444932039713369">"ഓണാണ്"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"ലഭ്യമല്ല"</item>
     <item msgid="8707481475312432575">"ഓഫാണ്"</item>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index f5bf05a..aad6a13 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Илүү олон виджет нэмэх"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджетүүдийг өөрчлөхийн тулд удаан дарна уу"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Виджетүүдийг өөрчлөх"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Виджетийг засах"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Хасах"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет нэмэх"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Хонх дуугаргах"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Чичиргэх"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Хаах"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Дамжуулах"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Хонхны дууг хаасан тул боломжгүй"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Дууг нь нээхийн тулд товшино уу."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Чичиргээнд тохируулахын тулд товшино уу. Хүртээмжийн үйлчилгээний дууг хаасан."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Дууг нь хаахын тулд товшино уу. Хүртээмжийн үйлчилгээний дууг хаасан."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Чичиргээнд тохируулахын тулд товшино уу."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Дууг хаахын тулд товшино уу."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Шуугианы хяналт"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Хонхны горимыг өөрчлөхийн тулд товшино уу"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"дууг хаах"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"дууг нээх"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Асаах/унтраах цэс"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>-н <xliff:g id="ID_1">%1$d</xliff:g>-р хуудас"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Түгжээтэй дэлгэц"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Хянамж болгоомжийн алхмыг харах"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Хянамж болгоомжийн алхмыг харах"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Төхөөрөмжөө салгана уу"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Тэмдэглэл хөтлөх"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Тэмдэглэл хөтлөх, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Аудио хуваалцаж байна"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Нэвтрүүлэлт"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г нэвтрүүлэхээ зогсоох уу?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Хэрэв та <xliff:g id="SWITCHAPP">%1$s</xliff:g>-г нэвтрүүлсэн эсвэл гаралтыг өөрчилсөн бол таны одоогийн нэвтрүүлэлтийг зогсооно"</string>
diff --git a/packages/SystemUI/res/values-mn/tiles_states_strings.xml b/packages/SystemUI/res/values-mn/tiles_states_strings.xml
index 33f3596..0db1229 100644
--- a/packages/SystemUI/res/values-mn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mn/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Унтраалттай"</item>
     <item msgid="578444932039713369">"Асаалттай"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Боломжгүй"</item>
     <item msgid="8707481475312432575">"Унтраалттай"</item>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index f9d4aca..d7acf5f 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"आणखी विजेट जोडा"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेट कस्टमाइझ करण्यासाठी प्रेस करून ठेवा"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"विजेट कस्टमाइझ करा"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"विजेट संपादित करा"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"काढून टाका"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट जोडा"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"रिंग करा"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"व्हायब्रेट"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"म्यूट करा"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"कास्ट करा"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"रिंग म्यूट केल्यामुळे उपलब्ध नाही"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. अनम्यूट करण्यासाठी टॅप करा."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. व्हायब्रेट सेट करण्यासाठी टॅप करा. प्रवेशयोग्यता सेवा म्यूट केल्या जाऊ शकतात."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. म्यूट करण्यासाठी टॅप करा. प्रवेशक्षमता सेवा म्यूट केल्या जाऊ शकतात."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. व्हायब्रेट सेट करण्यासाठी टॅप करा."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. म्यूट करण्यासाठी टॅप करा."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"नॉइझ कंट्रोल"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"रिंगर मोड बदलण्यासाठी टॅप करा"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्यूट करा"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"म्यूट काढून टाका"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"पॉवर मेनू"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> पैकी <xliff:g id="ID_1">%1$d</xliff:g> पेज"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"लॉक स्‍क्रीन"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"काय काळजी घ्यावी ते पहा"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"काय काळजी घ्यावी ते पहा"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"तुमचे डिव्हाइस अनप्लग करा"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"नोंद घेणे"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"नोंद घेणे, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"ऑडिओ शेअर करत आहे"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ब्रॉडकास्ट करत आहे"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> चे प्रसारण थांबवायचे आहे का?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"तुम्ही <xliff:g id="SWITCHAPP">%1$s</xliff:g> चे प्रसारण केल्यास किंवा आउटपुट बदलल्यास, तुमचे सध्याचे प्रसारण बंद होईल"</string>
diff --git a/packages/SystemUI/res/values-mr/tiles_states_strings.xml b/packages/SystemUI/res/values-mr/tiles_states_strings.xml
index 24d3b47..b70a5cc 100644
--- a/packages/SystemUI/res/values-mr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mr/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"बंद आहे"</item>
     <item msgid="578444932039713369">"सुरू आहे"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"उपलब्ध नाही"</item>
     <item msgid="8707481475312432575">"बंद आहे"</item>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index dafcfe0..03cd0a0 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Tambahkan lagi widget"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tekan lama untuk menyesuaikan widget"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Sesuaikan widget"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Alih keluar"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tambahkan widget"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Dering"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Getar"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Redam"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Hantar"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Tidak tersedia kerana deringan diredam"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Ketik untuk menyahredam."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Ketik untuk menetapkan pada getar. Perkhidmatan kebolehaksesan mungkin diredamkan."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ketik untuk meredam. Perkhidmatan kebolehaksesan mungkin diredamkan."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Ketik untuk menetapkan pada getar."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ketik untuk meredam."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Kawalan Hingar"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Ketik untuk menukar mod pendering"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"redam"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"nyahredam"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu kuasa"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> daripada <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Kunci skrin"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Lihat langkah penjagaan"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Lihat langkah penjagaan"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Cabut palam peranti anda"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Pengambilan nota"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Pengambilan nota, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Perkongsian audio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Menyiarkan"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hentikan siaran <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jika anda siarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g> atau tukarkan output, siaran semasa anda akan berhenti"</string>
diff --git a/packages/SystemUI/res/values-ms/tiles_states_strings.xml b/packages/SystemUI/res/values-ms/tiles_states_strings.xml
index 07a8426..b72a375 100644
--- a/packages/SystemUI/res/values-ms/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ms/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Mati"</item>
     <item msgid="578444932039713369">"Hidup"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Tidak tersedia"</item>
     <item msgid="8707481475312432575">"Mati"</item>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index e52b899..c6d46bc 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"နောက်ထပ်ဝိဂျက်များ ထည့်ရန်"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ဝိဂျက်များ စိတ်ကြိုက်လုပ်ရန် ကြာကြာနှိပ်ထားပါ"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ဝိဂျက်များကို စိတ်ကြိုက်လုပ်ရန်"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"ဝိဂျက်ပြင်ရန်"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"ဖယ်ရှားရန်"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ဝိဂျက်ထည့်ရန်"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"အသံမြည်သည်"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"တုန်ခါသည်"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"အသံတိတ်သည်"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"ကာစ်လုပ်ရန်"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"ဖုန်းမြည်သံပိတ်ထားသဖြင့် မရနိုင်ပါ"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s။ အသံပြန်ဖွင့်ရန် တို့ပါ။"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s။ တုန်ခါမှုကို သတ်မှတ်ရန် တို့ပါ။ အများသုံးနိုင်မှု ဝန်ဆောင်မှုများကို အသံပိတ်ထားနိုင်ပါသည်။"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s။ အသံပိတ်ရန် တို့ပါ။ အများသုံးနိုင်မှု ဝန်ဆောင်မှုများကို အသံပိတ်ထားနိုင်ပါသည်။"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s။ တုန်ခါခြင်းသို့ သတ်မှတ်ရန်တို့ပါ။"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s။ အသံပိတ်ရန် တို့ပါ။"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"ဆူညံသံ ထိန်းချုပ်ရန်"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"ဖုန်းခေါ်သံမုဒ်သို့ ပြောင်းရန် တို့ပါ"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"အသံပိတ်ရန်"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"အသံဖွင့်ရန်"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ပါဝါမီနူး"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"စာမျက်နှာ <xliff:g id="ID_2">%2$d</xliff:g> အနက်မှ စာမျက်နှာ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"လော့ခ်ချထားချိန် မျက်နှာပြင်"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ဂရုပြုစရာ အဆင့်များ ကြည့်ရန်"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ဂရုပြုစရာ အဆင့်များ ကြည့်ရန်"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"သင့်စက်ကို ပလတ်ဖြုတ်ပါ"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>၊ <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"မှတ်စုလိုက်ခြင်း"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"မှတ်စုလိုက်ခြင်း၊ <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"အသံမျှဝေခြင်း"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ထုတ်လွှင့်ခြင်း"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ထုတ်လွှင့်ခြင်းကို ရပ်မလား။"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ကို ထုတ်လွှင့်သောအခါ (သို့) အထွက်ကို ပြောင်းသောအခါ သင့်လက်ရှိထုတ်လွှင့်ခြင်း ရပ်သွားမည်"</string>
diff --git a/packages/SystemUI/res/values-my/tiles_states_strings.xml b/packages/SystemUI/res/values-my/tiles_states_strings.xml
index fd375d4..d223dc9 100644
--- a/packages/SystemUI/res/values-my/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-my/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"ပိတ်"</item>
     <item msgid="578444932039713369">"ဖွင့်"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"မရနိုင်ပါ"</item>
     <item msgid="8707481475312432575">"ပိတ်"</item>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index ed6e293..a2b97ee 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Legg til flere moduler"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Trykk lenge for å tilpasse modulene"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Tilpass moduler"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Endre modul"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Fjern"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Legg til modul"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Ring"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibrer"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Ignorer"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Cast"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Utilgjengelig fordi ringelyden er kuttet"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Trykk for å slå på lyden."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Trykk for å angi vibrasjon. Lyden kan bli slått av for tilgjengelighetstjenestene."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Trykk for å slå av lyden. Lyden kan bli slått av for tilgjengelighetstjenestene."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Trykk for å angi vibrasjon."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Trykk for å slå av lyden."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Støykontroll"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Trykk for å endre ringemodus"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"kutt lyden"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå på lyden"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Av/på-meny"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Side <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Låseskjerm"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Se vedlikeholdstrinnene"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Se vedlikeholdstrinnene"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Koble fra enheten"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Notatskriving"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Notatskriving, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Deler lyd"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Kringkaster"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vil du stoppe kringkastingen av <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Hvis du kringkaster <xliff:g id="SWITCHAPP">%1$s</xliff:g> eller endrer utgangen, stopper den nåværende kringkastingen din"</string>
diff --git a/packages/SystemUI/res/values-nb/tiles_states_strings.xml b/packages/SystemUI/res/values-nb/tiles_states_strings.xml
index e4a81194..2ed0096 100644
--- a/packages/SystemUI/res/values-nb/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-nb/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Av"</item>
     <item msgid="578444932039713369">"På"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Utilgjengelig"</item>
     <item msgid="8707481475312432575">"Av"</item>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index fb7680d..1388a85 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"थप विजेटहरू हाल्नुहोस्"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेटहरू कस्टमाइज गर्न केही बेरसम्म थिच्नुहोस्"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"विजेटहरू कस्टमाइज गर्नुहोस्"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"विजेट सम्पादन गर्नुहोस्"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"हटाउनुहोस्"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट हाल्नुहोस्"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"घन्टी"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"कम्पन"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"म्युट गर्नुहोस्"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"कास्ट गर्नुहोस्"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"डिभाइस म्युट गरिएकाले यो सुविधा उपलब्ध छैन"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s। अनम्यूट गर्नाका लागि ट्याप गर्नुहोस्।"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s। कम्पनमा सेट गर्नाका लागि ट्याप गर्नुहोस्। पहुँच सम्बन्धी सेवाहरू म्यूट हुन सक्छन्।"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। म्यूट गर्नाका लागि ट्याप गर्नुहोस्। पहुँच सम्बन्धी सेवाहरू म्यूट हुन सक्छन्।"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। कम्पन मोडमा सेट गर्न ट्याप गर्नुहोस्।"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। म्यूट गर्न ट्याप गर्नुहोस्।"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"नोइज कन्ट्रोल"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"रिङ्गर मोड बदल्न ट्याप गर्नुहोस्"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्युट गर्नुहोस्"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"अनम्युट गर्नुहोस्"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"पावर मेनु"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> मध्ये पृष्ठ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"लक स्क्रिन"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"डिभाइसको हेरचाह गर्ने तरिका हेर्नुहोस्"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"डिभाइसको हेरचाह गर्ने तरिका हेर्नुहोस्"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"डिभाइस बिजुलीको स्रोतबाट निकाल्नुहोस्"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"नोट लेख्ने कार्य"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"नोट लेख्ने कार्य, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"अडियो सेयर गरिँदै छ"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"प्रसारण गरिँदै छ"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्रोडकास्ट गर्न छाड्ने हो?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"तपाईंले <xliff:g id="SWITCHAPP">%1$s</xliff:g> ब्रोडकास्ट गर्नुभयो वा आउटपुट परिवर्तन गर्नुभयो भने तपाईंको हालको ब्रोडकास्ट रोकिने छ"</string>
diff --git a/packages/SystemUI/res/values-ne/tiles_states_strings.xml b/packages/SystemUI/res/values-ne/tiles_states_strings.xml
index 5cf91e5..40159fb 100644
--- a/packages/SystemUI/res/values-ne/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ne/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"अफ छ"</item>
     <item msgid="578444932039713369">"अन छ"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"उपलब्ध छैन"</item>
     <item msgid="8707481475312432575">"अफ छ"</item>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index a649617..09156cf 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Meer widgets toevoegen"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Houd lang ingedrukt om widgets aan te passen"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Widgets aanpassen"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Widget bewerken"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Verwijderen"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget toevoegen"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Bellen"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Trillen"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Geluid staat uit"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Casten"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Niet beschikbaar, belgeluid staat uit"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tik om dempen op te heffen."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tik om in te stellen op trillen. Het geluid van toegankelijkheidsservices kan hierdoor uitgaan."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tik om te dempen. Het geluid van toegankelijkheidsservices kan hierdoor uitgaan."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tik om in te stellen op trillen."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tik om geluid uit te zetten."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Ruisonderdrukking"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Tik om de beltoonmodus te wijzigen"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"geluid uit"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"geluid aanzetten"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Aan/uit-menu"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Vergrendelscherm"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Onderhoudsstappen bekijken"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Onderhoudsstappen bekijken"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Je apparaat loskoppelen"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Aantekeningen maken"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Aantekeningen maken, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Audio delen"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Uitzending"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Uitzending van <xliff:g id="APP_NAME">%1$s</xliff:g> stopzetten?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Als je <xliff:g id="SWITCHAPP">%1$s</xliff:g> uitzendt of de uitvoer wijzigt, wordt je huidige uitzending gestopt"</string>
@@ -1236,9 +1246,9 @@
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standaard notitie-app instellen in Instellingen"</string>
     <string name="install_app" msgid="5066668100199613936">"App installeren"</string>
     <string name="dismissible_keyguard_swipe" msgid="8377597870094949432">"Swipe omhoog om door te gaan"</string>
-    <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Spiegelen naar extern scherm?"</string>
+    <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirroren naar extern scherm?"</string>
     <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Het scherm aan de binnenkant wordt gemirrord. Het scherm aan de voorkant wordt uitgezet."</string>
-    <string name="mirror_display" msgid="2515262008898122928">"Scherm spiegelen"</string>
+    <string name="mirror_display" msgid="2515262008898122928">"Scherm mirroren"</string>
     <string name="dismiss_dialog" msgid="2195508495854675882">"Sluiten"</string>
     <string name="connected_display_icon_desc" msgid="6373560639989971997">"Scherm verbonden"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfoon en camera"</string>
diff --git a/packages/SystemUI/res/values-nl/tiles_states_strings.xml b/packages/SystemUI/res/values-nl/tiles_states_strings.xml
index 592ecf5..60e35da 100644
--- a/packages/SystemUI/res/values-nl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-nl/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Uit"</item>
     <item msgid="578444932039713369">"Aan"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Niet beschikbaar"</item>
     <item msgid="8707481475312432575">"Uit"</item>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index b0f5022..b49c297 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -287,7 +287,7 @@
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"ମିଡିଆ ଡିଭାଇସ୍‌"</string>
     <string name="quick_settings_user_title" msgid="8673045967216204537">"ୟୁଜର"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"ୱାଇ-ଫାଇ"</string>
-    <string name="quick_settings_internet_label" msgid="6603068555872455463">"ଇଣ୍ଟରନେଟ"</string>
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"ଇଣ୍ଟର୍ନେଟ"</string>
     <string name="quick_settings_networks_available" msgid="1875138606855420438">"ନେଟୱାର୍କଗୁଡ଼ିକ ଉପଲବ୍ଧ"</string>
     <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ନେଟୱାର୍କ ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"କୌଣସି ୱାଇ-ଫାଇ ନେଟ୍‌ୱର୍କ ଉପଲବ୍ଧ ନାହିଁ"</string>
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ଅଧିକ ୱିଜେଟ ଯୋଗ କରନ୍ତୁ"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ୱିଜେଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରିବା ପାଇଁ ଅଧିକ ସମୟ ଦବାନ୍ତୁ"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ୱିଜେଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରନ୍ତୁ"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"ୱିଜେଟକୁ ଏଡିଟ କରନ୍ତୁ"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"କାଢ଼ି ଦିଅନ୍ତୁ"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ୱିଜେଟ ଯୋଗ କରନ୍ତୁ"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"ରିଙ୍ଗ"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"ଭାଇବ୍ରେଟ୍‌"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"ମ୍ୟୁଟ"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"କାଷ୍ଟ କରନ୍ତୁ"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"ରିଂକୁ ମ୍ୟୁଟ କରାଯାଇଥିବା ଯୋଗୁଁ ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s। ଅନମ୍ୟୁଟ୍‍ କରିବା ପାଇଁ ଟାପ୍‍ କରନ୍ତୁ।"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s। ଭାଇବ୍ରେଟ୍‍ ସେଟ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ। ଆକ୍ସେସିବିଲିଟୀ ସର୍ଭିସ୍‌ ମ୍ୟୁଟ୍‍ କରାଯାଇପାରେ।"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। ମ୍ୟୁଟ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ। ଆକ୍ସେସିବିଲିଟୀ ସର୍ଭିସ୍‌ ମ୍ୟୁଟ୍‍ କରାଯାଇପାରେ।"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। ଭାଇବ୍ରେଟରେ ସେଟ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ।"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। ମ୍ୟୁଟ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ।"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"ନଏଜ କଣ୍ଟ୍ରୋଲ"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"ରିଙ୍ଗର୍ ମୋଡ୍ ବଦଳାଇବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ମ୍ୟୁଟ"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ଅନ୍‍-ମ୍ୟୁଟ୍ କରନ୍ତୁ"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ପାୱାର ମେନୁ"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"ପୃଷ୍ଠା <xliff:g id="ID_1">%1$d</xliff:g> ମୋଟ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"ଲକ ସ୍କ୍ରିନ"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ଯତ୍ନ ନେବା ପାଇଁ ଷ୍ଟେପଗୁଡ଼ିକ ଦେଖନ୍ତୁ"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ଯତ୍ନ ନେବା ପାଇଁ ଷ୍ଟେପଗୁଡ଼ିକ ଦେଖନ୍ତୁ"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"ଆପଣଙ୍କ ଡିଭାଇସକୁ ଅନପ୍ଲଗ କରନ୍ତୁ"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"ନୋଟ-ଟେକିଂ"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"ନୋଟ-ଟେକିଂ, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"ଅଡିଓ ସେୟାର କରାଯାଉଛି"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ବ୍ରଡକାଷ୍ଟ କରୁଛି"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବ୍ରଡକାଷ୍ଟ କରିବା ବନ୍ଦ କରିବେ?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ଯଦି ଆପଣ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ବ୍ରଡକାଷ୍ଟ କରନ୍ତି କିମ୍ବା ଆଉଟପୁଟ ବଦଳାନ୍ତି, ତେବେ ଆପଣଙ୍କ ବର୍ତ୍ତମାନର ବ୍ରଡକାଷ୍ଟ ବନ୍ଦ ହୋଇଯିବ"</string>
diff --git a/packages/SystemUI/res/values-or/tiles_states_strings.xml b/packages/SystemUI/res/values-or/tiles_states_strings.xml
index d362c65f..43bddbf 100644
--- a/packages/SystemUI/res/values-or/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-or/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"ବନ୍ଦ ଅଛି"</item>
     <item msgid="578444932039713369">"ଚାଲୁ ଅଛି"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"ଉପଲବ୍ଧ ନାହିଁ"</item>
     <item msgid="8707481475312432575">"ବନ୍ଦ ଅଛି"</item>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 6916fd2..cd55198 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ਹੋਰ ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ਵਿਜੇਟਾਂ ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰਨ ਲਈ ਦਬਾਈ ਰੱਖੋ"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ਵਿਜੇਟ ਵਿਉਂਤਬੱਧ ਕਰੋ"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"ਵਿਜੇਟ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"ਹਟਾਓ"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰੋ"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"ਘੰਟੀ"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"ਥਰਥਰਾਹਟ"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"ਮਿਊਟ"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"ਕਾਸਟ ਕਰੋ"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"ਉਪਲਬਧ ਨਹੀਂ ਹੈ ਕਿਉਂਕਿ ਘੰਟੀ ਮਿਊਟ ਕੀਤੀ ਹੋਈ ਹੈ"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s। ਅਣਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s। ਥਰਥਰਾਹਟ ਸੈੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ। ਪਹੁੰਚਯੋਗਤਾ ਸੇਵਾਵਾਂ ਮਿਊਟ ਹੋ ਸਕਦੀਆਂ ਹਨ।"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। ਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ। ਪਹੁੰਚਯੋਗਤਾ ਸੇਵਾਵਾਂ ਮਿਊਟ ਹੋ ਸਕਦੀਆਂ ਹਨ।"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। ਥਰਥਰਾਹਟ \'ਤੇ ਸੈੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। ਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"ਸ਼ੋਰ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"ਰਿੰਗਰ ਮੋਡ ਨੂੰ ਬਦਲਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ਮਿਊਟ ਕਰੋ"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ਅਣਮਿਊਟ ਕਰੋ"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ਪਾਵਰ ਮੀਨੂ"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> ਦਾ <xliff:g id="ID_1">%1$d</xliff:g> ਪੰਨਾ"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">" ਲਾਕ  ਸਕ੍ਰੀਨ"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ਦੇਖਭਾਲ ਦੇ ਪੜਾਅ ਦੇਖੋ"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ਦੇਖਭਾਲ ਦੇ ਪੜਾਅ ਦੇਖੋ"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"ਆਪਣਾ ਡੀਵਾਈਸ ਅਣਪਲੱਗ ਕਰੋ"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"ਨੋਟ ਬਣਾਉਣਾ"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"ਨੋਟ ਬਣਾਉਣਾ, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"ਆਡੀਓ ਨੂੰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ਪ੍ਰਸਾਰਨ"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਦੇ ਪ੍ਰਸਾਰਨ ਨੂੰ ਰੋਕਣਾ ਹੈ?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ਜੇ ਤੁਸੀਂ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ਦਾ ਪ੍ਰਸਾਰਨ ਕਰਦੇ ਹੋ ਜਾਂ ਆਊਟਪੁੱਟ ਬਦਲਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡਾ ਮੌਜੂਦਾ ਪ੍ਰਸਾਰਨ ਰੁਕ ਜਾਵੇਗਾ"</string>
diff --git a/packages/SystemUI/res/values-pa/tiles_states_strings.xml b/packages/SystemUI/res/values-pa/tiles_states_strings.xml
index f249afb..5f0ca17 100644
--- a/packages/SystemUI/res/values-pa/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pa/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"ਬੰਦ ਹੈ"</item>
     <item msgid="578444932039713369">"ਚਾਲੂ ਹੈ"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"ਅਣਉਪਲਬਧ ਹੈ"</item>
     <item msgid="8707481475312432575">"ਬੰਦ ਹੈ"</item>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index c04d6da..76547ed 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodaj więcej widżetów"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Przytrzymaj, aby dostosować widżety"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Dostosuj widżety"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Edytuj widżet"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Usuń"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj widżet"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Dzwonek"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Wibracje"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Wyciszenie"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Przesyłanie"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Niedostępne, bo dzwonek jest wyciszony"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Kliknij, by wyłączyć wyciszenie."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Kliknij, by włączyć wibracje. Ułatwienia dostępu mogą być wyciszone."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Kliknij, by wyciszyć. Ułatwienia dostępu mogą być wyciszone."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Kliknij, by włączyć wibracje."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Kliknij, by wyciszyć."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Tłumienie szumów"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Kliknij, aby zmienić tryb dzwonka"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"wycisz"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"wyłącz wyciszenie"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu zasilania"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Strona <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Ekran blokady"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Zobacz instrukcję postępowania"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobacz instrukcję postępowania"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Odłącz urządzenie"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Notatki"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Notatki, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Udostępnia dźwięk"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmisja"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zatrzymaj transmisję aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jeśli transmitujesz aplikację <xliff:g id="SWITCHAPP">%1$s</xliff:g> lub zmieniasz dane wyjściowe, Twoja obecna transmisja zostanie zakończona"</string>
diff --git a/packages/SystemUI/res/values-pl/tiles_states_strings.xml b/packages/SystemUI/res/values-pl/tiles_states_strings.xml
index ea6ad58..5e3a118 100644
--- a/packages/SystemUI/res/values-pl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pl/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Wyłączony"</item>
     <item msgid="578444932039713369">"Włączony"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Niedostępne"</item>
     <item msgid="8707481475312432575">"Wyłączone"</item>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index e82a103..598ef78 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adicione mais widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha pressionado para personalizar widgets"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Tocar"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibrar"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Desativar som"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Transmitir"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Indisponível com o toque foi silenciado"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toque para ativar o som."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toque para configurar para vibrar. É possível que os serviços de acessibilidade sejam silenciados."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para silenciar. É possível que os serviços de acessibilidade sejam silenciados."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toque para configurar para vibrar."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toque para silenciar."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Controle de ruído"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Toque para mudar o modo da campainha"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar o som"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ativar o som"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu liga/desliga"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Tela de bloqueio"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver etapas de cuidado"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver etapas de cuidado"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Desconecte seu dispositivo"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Anotações"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Anotações, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Compartilhando áudio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmitindo"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Interromper a transmissão do app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se você transmitir o app <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou mudar a saída, a transmissão atual será interrompida"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
index 28c07f4..d4fd838 100644
--- a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Desativada"</item>
     <item msgid="578444932039713369">"Ativada"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Indisponível"</item>
     <item msgid="8707481475312432575">"Desativado"</item>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 8ba907b..7e5a736 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -429,6 +429,7 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adicionar mais widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha premido para personalizar os widgets"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
+    <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ícone da app do widget desativado"</string>
     <string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string>
@@ -573,11 +574,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Toque"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibrar"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Desativar som"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Transmitir"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Indisponível porque o toque está desat."</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toque para reativar o som."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toque para ativar a vibração. Os serviços de acessibilidade podem ser silenciados."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para desativar o som. Os serviços de acessibilidade podem ser silenciados."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toque para ativar a vibração."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toque para desativar o som."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Controlo de ruído"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Toque para alterar o modo de campainha"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar som"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"reativar som"</string>
@@ -832,6 +836,8 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu ligar/desligar"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Ecrã de bloqueio"</string>
+    <string name="finder_active" msgid="7907846989716941952">"Pode localizar este telemóvel com o serviço Localizar o meu dispositivo mesmo quando está desligado"</string>
+    <string name="shutdown_progress" msgid="5464239146561542178">"A encerrar…"</string>
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Veja os passos de manutenção"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Veja os passos de manutenção"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Desligue o dispositivo"</string>
@@ -1186,6 +1192,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Tomar notas"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Tomar notas, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"A partilhar áudio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"A transmitir"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Interromper a transmissão da app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se transmitir a app <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou alterar a saída, a sua transmissão atual é interrompida"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
index b58b848..e94b1ec 100644
--- a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Desligado"</item>
     <item msgid="578444932039713369">"Ligado"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Indisponível"</item>
     <item msgid="8707481475312432575">"Desligado"</item>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index e82a103..598ef78 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adicione mais widgets"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha pressionado para personalizar widgets"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Tocar"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibrar"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Desativar som"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Transmitir"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Indisponível com o toque foi silenciado"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Toque para ativar o som."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Toque para configurar para vibrar. É possível que os serviços de acessibilidade sejam silenciados."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para silenciar. É possível que os serviços de acessibilidade sejam silenciados."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toque para configurar para vibrar."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toque para silenciar."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Controle de ruído"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Toque para mudar o modo da campainha"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar o som"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ativar o som"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu liga/desliga"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Tela de bloqueio"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver etapas de cuidado"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver etapas de cuidado"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Desconecte seu dispositivo"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Anotações"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Anotações, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Compartilhando áudio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmitindo"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Interromper a transmissão do app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se você transmitir o app <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou mudar a saída, a transmissão atual será interrompida"</string>
diff --git a/packages/SystemUI/res/values-pt/tiles_states_strings.xml b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
index 28c07f4..d4fd838 100644
--- a/packages/SystemUI/res/values-pt/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Desativada"</item>
     <item msgid="578444932039713369">"Ativada"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Indisponível"</item>
     <item msgid="8707481475312432575">"Desativado"</item>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 8cd2d77..026e22b 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adaugă mai multe widgeturi"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Apasă lung pentru a personaliza widgeturi"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizează widgeturile"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Editează widgetul"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Elimină"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adaugă un widget"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Sonerie"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibrații"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Blochează"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Proiectează"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Indisponibil; soneria este dezactivată"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Atinge pentru a activa sunetul."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Atinge pentru a seta vibrarea. Sunetul se poate dezactiva pentru serviciile de accesibilitate."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Atinge pentru a dezactiva sunetul. Sunetul se poate dezactiva pentru serviciile de accesibilitate."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Atinge pentru a seta pe vibrații."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Atinge pentru a dezactiva sunetul."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Controlul zgomotului"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Atinge pentru a schimba modul soneriei"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"dezactivează sunetul"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"activează sunetul"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Meniul de pornire"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> din <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Ecran de blocare"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Vezi pașii pentru îngrijire"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Vezi pașii pentru îngrijire"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Deconectează dispozitivul"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Luare de notițe"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Luare de notițe, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Se permite accesul la conținutul audio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Se difuzează"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Oprești transmisia <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Dacă transmiți <xliff:g id="SWITCHAPP">%1$s</xliff:g> sau schimbi ieșirea, transmisia actuală se va opri"</string>
diff --git a/packages/SystemUI/res/values-ro/tiles_states_strings.xml b/packages/SystemUI/res/values-ro/tiles_states_strings.xml
index 5a5eb9f..75565f9 100644
--- a/packages/SystemUI/res/values-ro/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ro/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Dezactivată"</item>
     <item msgid="578444932039713369">"Activată"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Indisponibilă"</item>
     <item msgid="8707481475312432575">"Dezactivată"</item>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 614eb06..1df112b 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Добавить виджеты"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Нажмите и удерживайте, чтобы настроить виджеты."</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Настроить виджеты"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Изменить виджет"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Удалить"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Добавить виджет"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Со звуком"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Вибрация"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Без звука"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Трансляция"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Недоступно, когда отключен звук вызовов"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Нажмите, чтобы включить звук."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Нажмите, чтобы включить вибрацию. Специальные возможности могут прекратить работу."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Нажмите, чтобы выключить звук. Специальные возможности могут прекратить работу."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Нажмите, чтобы включить вибрацию."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Нажмите, чтобы выключить звук."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Контроль уровня шума"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Нажмите, чтобы изменить режим звонка."</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"отключить звук"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"включить звук"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Меню кнопки питания"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Страница <xliff:g id="ID_1">%1$d</xliff:g> из <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Заблокированный экран"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Подробнее о действиях при перегреве…"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Подробнее о действиях при перегреве…"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Отключите устройство"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Создание заметок"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>: создание заметок"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Передает аудио"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Трансляция"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Остановить трансляцию \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Если вы начнете транслировать \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\" или смените целевое устройство, текущая трансляция прервется."</string>
diff --git a/packages/SystemUI/res/values-ru/tiles_states_strings.xml b/packages/SystemUI/res/values-ru/tiles_states_strings.xml
index cd14079..3099e00 100644
--- a/packages/SystemUI/res/values-ru/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ru/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Откл."</item>
     <item msgid="578444932039713369">"Вкл."</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Функция недоступна"</item>
     <item msgid="8707481475312432575">"Откл."</item>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index d1bcee4..f4b7d1e 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"තවත් විජට් එක් කරන්න"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"විජට් අභිරුචිකරණය කිරීමට දිගු ඔබන්න"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"විජට්ටු අභිරුචි කරන්න"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"විජට්ටු සංස්කරණ කරන්න"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"ඉවත් කරන්න"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"විජට්ටුව එක් කරන්න"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"නාද කරන්න"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"කම්පනය කරන්න"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"නිහඬ කරන්න"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"විකාශය"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"නාදය නිහඬ කර ඇති නිසා නොලැබේ"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. නිහඬ කිරීම ඉවත් කිරීමට තට්ටු කරන්න."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. කම්පනය කිරීමට තට්ටු කරන්න. ප්‍රවේශ්‍යතා සේවා නිහඬ කළ හැකිය."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. නිහඬ කිරීමට තට්ටු කරන්න. ප්‍රවේශ්‍යතා සේවා නිහඬ කළ හැකිය."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. කම්පනය කිරීමට සකස් කිරීමට තට්ටු කරන්න."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. නිහඬ කිරීමට තට්ටු කරන්න."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"ඝෝෂාව පාලනය"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"නාදකය වෙනස් කිරීමට තට්ටු කරන්න"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"නිහඬ කරන්න"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"නිශ්ශබ්දතාවය ඉවත් කරන්න"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"බල මෙනුව"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> න් <xliff:g id="ID_1">%1$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"අගුලු තිරය"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"රැකවරණ පියවර බලන්න"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"රැකවරණ පියවර බලන්න"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"ඔබේ උපාංගය ගලවන්න"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"සටහන් කර ගැනීම"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"සටහන් කර ගැනීම, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"ශ්‍රව්‍ය බෙදා ගැනීම"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"විකාශනය කරමින්"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> විකාශනය කිරීම නවත්වන්නද?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ඔබ <xliff:g id="SWITCHAPP">%1$s</xliff:g> විකාශනය කළහොත් හෝ ප්‍රතිදානය වෙනස් කළහොත්, ඔබගේ වත්මන් විකාශනය නවතිනු ඇත."</string>
diff --git a/packages/SystemUI/res/values-si/tiles_states_strings.xml b/packages/SystemUI/res/values-si/tiles_states_strings.xml
index fcd768b..48e8cc4 100644
--- a/packages/SystemUI/res/values-si/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-si/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"අක්‍රියයි"</item>
     <item msgid="578444932039713369">"සක්‍රියයි"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"නොමැත"</item>
     <item msgid="8707481475312432575">"අක්‍රියයි"</item>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 3e2b554..0f579da 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Pridať ďalšie miniaplikácie"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Miniaplikácie prispôsobíte dlhým stlačením"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prispôsobiť miniaplikácie"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Upraviť miniaplikáciu"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Odstrániť"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pridať miniaplikáciu"</string>
@@ -530,7 +532,7 @@
     <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Toto zariadenie spravuje tvoj rodič. Vidí a môže spravovať informácie, napríklad aplikácie, ktoré používaš, tvoju polohu a čas používania."</string>
     <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Odomknutie udržiava TrustAgent"</string>
-    <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Ochrana pred krádež.\nZar. uzamknuté, priveľa pokusov o odomk."</string>
+    <string name="kg_prompt_after_adaptive_auth_lock" msgid="1265107698772588299">"Ochrana pred krádežou\nUzamknuté, priveľa pokusov o odomknutie"</string>
     <string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
     <string name="accessibility_volume_settings" msgid="1458961116951564784">"Nastavenia zvuku"</string>
     <string name="volume_odi_captions_tip" msgid="8825655463280990941">"Automatické titulkovanie médií"</string>
@@ -573,19 +575,22 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Prezvoniť"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibrovať"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Vypnúť zvuk"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Prenos"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nedostupné, pretože je vypnuté zvonenie"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Klepnutím zapnite zvuk."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Klepnutím aktivujte režim vibrovania. Služby dostupnosti je možné stlmiť."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Klepnutím vypnite zvuk. Služby dostupnosti je možné stlmiť."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Klepnutím nastavíte vibrovanie."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Klepnutím vypnete zvuk."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Ovládanie šumu"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Režim zvonenia zmeníte klepnutím"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vypnite zvuk"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"zapnite zvuk"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"zapnite vibrovanie"</string>
     <string name="volume_dialog_title" msgid="6502703403483577940">"Ovládacie prvky hlasitosti %s"</string>
     <string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"Hovory a upozornenia spustia zvonenie (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
-    <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> sa prehráva v zar."</string>
-    <string name="media_output_title_without_playing" msgid="3825663683169305013">"Zvuk prehrá zariad.:"</string>
+    <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> sa prehráva v:"</string>
+    <string name="media_output_title_without_playing" msgid="3825663683169305013">"Zvuk sa prehrá v:"</string>
     <string name="system_ui_tuner" msgid="1471348823289954729">"Tuner používateľského rozhrania systému"</string>
     <string name="status_bar" msgid="4357390266055077437">"Stavový riadok"</string>
     <string name="demo_mode" msgid="263484519766901593">"Ukážka používateľského rozhrania systému"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Ponuka vypínača"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Strana <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Uzamknutá obrazovka"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Zobraziť opatrenia"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobraziť opatrenia"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Odpojte zariadenie"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Zapisovanie poznámok"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Zapisovanie poznámok, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Zdieľa sa zvuk"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Vysiela"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Chcete zastaviť vysielanie aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ak vysielate aplikáciu <xliff:g id="SWITCHAPP">%1$s</xliff:g> alebo zmeníte výstup, aktuálne vysielanie bude zastavené"</string>
diff --git a/packages/SystemUI/res/values-sk/tiles_states_strings.xml b/packages/SystemUI/res/values-sk/tiles_states_strings.xml
index 660f85d..fdfcd27db 100644
--- a/packages/SystemUI/res/values-sk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sk/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Vypnuté"</item>
     <item msgid="578444932039713369">"Zapnuté"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Nie je k dispozícii"</item>
     <item msgid="8707481475312432575">"Vypnuté"</item>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 1ea97a1..7acaa54 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodajte več pripomočkov"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pridržite za prilagajanje pripomočkov"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prilagajanje pripomočkov"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Urejanje pripomočka"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Odstrani"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodajanje pripomočka"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Zvonjenje"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibriranje"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Utišano"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Predvajanje"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Ni na voljo, ker je zvonjenje izklopljeno"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Dotaknite se, če želite vklopiti zvok."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Dotaknite se, če želite nastaviti vibriranje. V storitvah za dostopnost bo morda izklopljen zvok."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dotaknite se, če želite izklopiti zvok. V storitvah za dostopnost bo morda izklopljen zvok."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dotaknite se, če želite nastaviti vibriranje."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dotaknite se, če želite izklopiti zvok."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Omejevanje hrupa"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Dotaknite se, če želite spremeniti način zvonjenja."</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"izklop zvoka"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"vklop zvoka"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Meni za vklop/izklop"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. stran od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Zaklenjen zaslon"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Oglejte si navodila za ukrepanje"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Oglejte si navodila za ukrepanje"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Odklopite napravo"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Ustvarjanje zapiskov"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Ustvarjanje zapiskov, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Deljenje zvoka"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Oddajanje"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Želite ustaviti oddajanje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Če oddajate aplikacijo <xliff:g id="SWITCHAPP">%1$s</xliff:g> ali spremenite izhod, bo trenutno oddajanje ustavljeno."</string>
diff --git a/packages/SystemUI/res/values-sl/tiles_states_strings.xml b/packages/SystemUI/res/values-sl/tiles_states_strings.xml
index d7e62ca..3804d63 100644
--- a/packages/SystemUI/res/values-sl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sl/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Izklopljeno"</item>
     <item msgid="578444932039713369">"Vklopljeno"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Ni na voljo"</item>
     <item msgid="8707481475312432575">"Izklopljeno"</item>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index c3ccd81..21a974f 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Shto miniaplikacione të tjera"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Shtyp gjatë për të personalizuar miniaplikacionet"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizo miniaplikacionet"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Modifiko miniaplikacionin"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Hiq"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Shto miniaplikacionin"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Bjeri ziles"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Dridhje"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Pa zë"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Transmeto"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Nuk ofrohet; ziles i është hequr zëri"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Trokit për të aktivizuar."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Trokit për ta caktuar te dridhja. Shërbimet e qasshmërisë mund të çaktivizohen."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Trokit për të çaktivizuar. Shërbimet e qasshmërisë mund të çaktivizohen."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Trokit për ta vendosur në dridhje."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Trokit për ta çaktivizuar."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Kontrolli i zhurmës"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Trokit për të ndryshuar modalitetin e ziles"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"çaktivizo audion"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktivizo audion"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menyja e energjisë"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Faqja <xliff:g id="ID_1">%1$d</xliff:g> nga <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Ekrani i kyçjes"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Shiko hapat për kujdesin"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Shiko hapat për kujdesin"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Shkëpute pajisjen"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Mbajtja e shënimeve"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Mbajtja e shënimeve, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Po ndahet audio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Po transmeton"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Të ndalohet transmetimi i <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Nëse transmeton <xliff:g id="SWITCHAPP">%1$s</xliff:g> ose ndryshon daljen, transmetimi yt aktual do të ndalojë"</string>
diff --git a/packages/SystemUI/res/values-sq/tiles_states_strings.xml b/packages/SystemUI/res/values-sq/tiles_states_strings.xml
index b8e1355..6318700 100644
--- a/packages/SystemUI/res/values-sq/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sq/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Joaktive"</item>
     <item msgid="578444932039713369">"Aktiv"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Nuk ofrohet"</item>
     <item msgid="8707481475312432575">"Joaktive"</item>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 2309d7d..2f52f90 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Додајте још виџета"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Дуги притисак за прилагођавање виџета"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Прилагоди виџете"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Измени виџет"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Уклони"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додај виџет"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Активирај звоно"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Вибрирај"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Искључи звук"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Пребацивање"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Недоступно јер је звук искључен"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Додирните да бисте укључили звук."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Додирните да бисте подесили на вибрацију. Звук услуга приступачности ће можда бити искључен."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Додирните да бисте искључили звук. Звук услуга приступачности ће можда бити искључен."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Додирните да бисте подесили на вибрацију."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Додирните да бисте искључили звук."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Контрола шума"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Додирните да бисте променили режим звона"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"искључите звук"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"укључите звук"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Мени дугмета за укључивање"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. страна од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Закључан екран"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Погледајте упозорења"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Погледајте упозорења"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Искључите уређај"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Прављење бележака"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Прављење бележака, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Дели се звук"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Емитовање"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Желите да зауставите емитовање апликације <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ако емитујете апликацију <xliff:g id="SWITCHAPP">%1$s</xliff:g> или промените излаз, актуелно емитовање ће се зауставити"</string>
diff --git a/packages/SystemUI/res/values-sr/tiles_states_strings.xml b/packages/SystemUI/res/values-sr/tiles_states_strings.xml
index c959bfb..e4cf0b6 100644
--- a/packages/SystemUI/res/values-sr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sr/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Искључено"</item>
     <item msgid="578444932039713369">"Укључено"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Недоступно"</item>
     <item msgid="8707481475312432575">"Искључено"</item>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index be80f7a..20bc7e7 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Lägg till fler widgetar"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tryck länge för att anpassa widgetar"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Anpassa widgetar"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Redigera widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Ta bort"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lägg till widget"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Ringsignal"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Vibration"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Dölj"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Casta"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Otillgängligt eftersom ringljudet är av"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Tryck här om du vill slå på ljudet."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tryck här om du vill sätta på vibrationen. Tillgänglighetstjänster kanske inaktiveras."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tryck här om du vill stänga av ljudet. Tillgänglighetstjänsterna kanske inaktiveras."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tryck här om du vill aktivera vibrationsläget."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tryck här om du vill stänga av ljudet."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Bruskontroll"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Tryck för att ändra ringsignalens läge"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"stänga av ljudet"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå på ljudet"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Startmeny"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Sida <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Låsskärm"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Visa alla skötselråd"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Visa alla skötselråd"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Koppla ur enheten"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Anteckna"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Anteckna med <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Delar ljud"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Sänder"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vill du sluta sända från <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Om en utsändning från <xliff:g id="SWITCHAPP">%1$s</xliff:g> pågår eller om du byter ljudutgång avbryts den nuvarande utsändningen"</string>
diff --git a/packages/SystemUI/res/values-sv/tiles_states_strings.xml b/packages/SystemUI/res/values-sv/tiles_states_strings.xml
index 28717df..8981ac7 100644
--- a/packages/SystemUI/res/values-sv/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sv/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Av"</item>
     <item msgid="578444932039713369">"På"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Inte tillgängligt"</item>
     <item msgid="8707481475312432575">"Av"</item>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 0999820..fa0e7b5 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Weka wijeti zingine"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Bonyeza kwa muda mrefu uweke mapendeleo ya wijeti"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Badilisha wijeti upendavyo"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Badilisha wijeti"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Ondoa"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ongeza wijeti"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Piga"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Kutetema"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Zima sauti"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Tuma"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Halipatikani kwa sababu sauti imezimwa"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Gusa ili urejeshe."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Gusa ili uweke mtetemo. Huenda ikakomesha huduma za zana za walio na matatizo ya kuona au kusikia."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Gusa ili ukomeshe. Huenda ikakomesha huduma za zana za walio na matatizo ya kuona au kusikia."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Gusa ili uweke mtetemo."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Gusa ili usitishe."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Kidhibiti cha Kelele"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Gusa ili ubadilishe hali ya programu inayotoa milio ya simu"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"zima sauti"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"washa sauti"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menyu ya kuzima/kuwasha"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Ukurasa wa <xliff:g id="ID_1">%1$d</xliff:g> kati ya <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Skrini iliyofungwa"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Angalia hatua za utunzaji"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Angalia hatua za utunzaji"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Chomoa kifaa chako"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Kuandika madokezo"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Kuandika madokezo, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Watu wengine wanasikia sauti"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Inaarifu"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Ungependa kusimamisha utangazaji kwenye <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ikiwa unatangaza kwenye <xliff:g id="SWITCHAPP">%1$s</xliff:g> au unabadilisha maudhui, tangazo lako la sasa litasimamishwa"</string>
diff --git a/packages/SystemUI/res/values-sw/tiles_states_strings.xml b/packages/SystemUI/res/values-sw/tiles_states_strings.xml
index 2fe4060..08a1f14 100644
--- a/packages/SystemUI/res/values-sw/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sw/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Kimezimwa"</item>
     <item msgid="578444932039713369">"Kimewashwa"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Hakipatikani"</item>
     <item msgid="8707481475312432575">"Kimezimwa"</item>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 486d7f9..0f360e6 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"கூடுதல் விட்ஜெட்களைச் சேருங்கள்"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"விட்ஜெட்களைப் பிரத்தியேகமாக்க நீண்ட நேரம் அழுத்துக"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"விட்ஜெட்களைப் பிரத்தியேகமாக்குங்கள்"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"விட்ஜெட்டைத் திருத்து"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"அகற்றும்"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"விட்ஜெட்டைச் சேர்"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"ஒலி"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"அதிர்வு"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"அமைதி"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"அலைபரப்பு"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"\'ரிங்\' மியூட்டில் உள்ளதால் கிடைக்கவில்லை"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. ஒலி இயக்க, தட்டவும்."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. அதிர்விற்கு அமைக்க, தட்டவும். அணுகல்தன்மை சேவைகள் ஒலியடக்கப்படக்கூடும்."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ஒலியடக்க, தட்டவும். அணுகல்தன்மை சேவைகள் ஒலியடக்கப்படக்கூடும்."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. அதிர்விற்கு அமைக்க, தட்டவும்."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. ஒலியடக்க, தட்டவும்."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"இரைச்சல் கட்டுப்பாடு"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"ரிங்கர் பயன்முறையை மாற்ற தட்டவும்"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ஒலியடக்கும்"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ஒலி இயக்கும்"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"பவர் மெனு"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"பக்கம் <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"லாக் ஸ்கிரீன்"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"மேலும் விவரங்களுக்கு இதைப் பார்க்கவும்"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"மேலும் விவரங்களுக்கு இதைப் பார்க்கவும்"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"சாதன இணைப்பைத் துண்டித்தல்"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"குறிப்பெடுத்தல்"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"குறிப்பெடுத்தல், <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"ஆடியோ பகிரப்படுகிறது"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ஒலிபரப்புதல்"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் ஒலிபரப்பப்படுவதை நிறுத்தவா?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"நீங்கள் <xliff:g id="SWITCHAPP">%1$s</xliff:g> ஆப்ஸை ஒலிபரப்பினாலோ அவுட்புட்டை மாற்றினாலோ உங்களின் தற்போதைய ஒலிபரப்பு நிறுத்தப்படும்"</string>
diff --git a/packages/SystemUI/res/values-ta/tiles_states_strings.xml b/packages/SystemUI/res/values-ta/tiles_states_strings.xml
index 5bcc6c7..741d6de 100644
--- a/packages/SystemUI/res/values-ta/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ta/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"முடக்கப்பட்டுள்ளது"</item>
     <item msgid="578444932039713369">"இயக்கப்பட்டுள்ளது"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"கிடைக்கவில்லை"</item>
     <item msgid="8707481475312432575">"முடக்கப்பட்டுள்ளது"</item>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 227ba5a..4e8e2d0 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"మరిన్ని విడ్జెట్‌లను జోడించండి"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"విడ్జెట్‌లను అనుకూలీకరించడానికి, నొక్కి, ఉంచండి"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"విడ్జెట్‌లను అనుకూలంగా మార్చండి"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"విడ్జెట్‌ను ఎడిట్ చేయండి"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"తీసివేయండి"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"విడ్జెట్‌ను జోడించండి"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"రింగ్"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"వైబ్రేట్"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"మ్యూట్"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"ప్రసారం చేయండి"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"వాల్యూమ్ మ్యూట్ అయినందున అందుబాటులో లేదు"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. అన్‌మ్యూట్ చేయడానికి నొక్కండి."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. వైబ్రేషన్‌కు సెట్ చేయడానికి నొక్కండి. యాక్సెస్ సామర్థ్య సేవలు మ్యూట్ చేయబడవచ్చు."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. మ్యూట్ చేయడానికి నొక్కండి. యాక్సెస్ సామర్థ్య సేవలు మ్యూట్ చేయబడవచ్చు."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. వైబ్రేట్ అయ్యేలా సెట్ చేయడం కోసం నొక్కండి."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. మ్యూట్ చేయడానికి నొక్కండి."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"నాయిస్ కంట్రోల్"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"రింగర్ మోడ్‌ను మార్చడానికి ట్యాప్ చేయండి"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"మ్యూట్ చేయి"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"అన్‌మ్యూట్ చేయి"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"పవర్ మెనూ"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>లో <xliff:g id="ID_1">%1$d</xliff:g>వ పేజీ"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"లాక్ స్క్రీన్"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"తీసుకోవాల్సిన జాగ్రత్తలు ఏమిటో చూడండి"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"తీసుకోవాల్సిన జాగ్రత్తలు ఏమిటో చూడండి"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"మీ పరికరాన్ని అన్‌ప్లగ్ చేయండి"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"నోట్-టేకింగ్"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"నోట్-టేకింగ్, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"ఆడియోను షేర్ చేస్తున్నారు"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ప్రసారం చేస్తోంది"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రసారం చేయడాన్ని ఆపివేయాలా?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"మీరు <xliff:g id="SWITCHAPP">%1$s</xliff:g> ప్రసారం చేస్తే లేదా అవుట్‌పుట్‌ను మార్చినట్లయితే, మీ ప్రస్తుత ప్రసారం ఆగిపోతుంది"</string>
diff --git a/packages/SystemUI/res/values-te/tiles_states_strings.xml b/packages/SystemUI/res/values-te/tiles_states_strings.xml
index 9d2b407..6ff2934 100644
--- a/packages/SystemUI/res/values-te/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-te/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"ఆఫ్‌లో ఉంది"</item>
     <item msgid="578444932039713369">"ఆన్‌లో ఉంది"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"అందుబాటులో లేదు"</item>
     <item msgid="8707481475312432575">"ఆఫ్‌లో ఉంది"</item>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index d1e186f..98075c5 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"เพิ่มวิดเจ็ตอีก"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"กดค้างเพื่อปรับแต่งวิดเจ็ต"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ปรับแต่งวิดเจ็ต"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"แก้ไขวิดเจ็ต"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"นำออก"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"เพิ่มวิดเจ็ต"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"ทำให้ส่งเสียง"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"สั่น"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"ปิดเสียง"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"แคสต์"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"เปลี่ยนไม่ได้เนื่องจากปิดเสียงเรียกเข้า"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s แตะเพื่อเปิดเสียง"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s แตะเพื่อตั้งค่าให้สั่น อาจมีการปิดเสียงบริการการเข้าถึง"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s แตะเพื่อปิดเสียง อาจมีการปิดเสียงบริการการเข้าถึง"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s แตะเพื่อตั้งค่าให้สั่น"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s แตะเพื่อปิดเสียง"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"การควบคุมเสียง"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"แตะเพื่อเปลี่ยนโหมดเสียงเรียกเข้า"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ปิดเสียง"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"เปิดเสียง"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"เมนูเปิด/ปิด"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"หน้า <xliff:g id="ID_1">%1$d</xliff:g> จาก <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"หน้าจอล็อก"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ดูขั้นตอนในการดูแลรักษา"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ดูขั้นตอนในการดูแลรักษา"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"ถอดปลั๊กอุปกรณ์"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"การจดบันทึก"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"การจดบันทึก <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"กำลังแชร์เสียง"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"กำลังออกอากาศ"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"หยุดการออกอากาศ <xliff:g id="APP_NAME">%1$s</xliff:g> ไหม"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"หากคุณออกอากาศ <xliff:g id="SWITCHAPP">%1$s</xliff:g> หรือเปลี่ยนแปลงเอาต์พุต การออกอากาศในปัจจุบันจะหยุดลง"</string>
diff --git a/packages/SystemUI/res/values-th/tiles_states_strings.xml b/packages/SystemUI/res/values-th/tiles_states_strings.xml
index 69449a7..d961385 100644
--- a/packages/SystemUI/res/values-th/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-th/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"ปิด"</item>
     <item msgid="578444932039713369">"เปิด"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"ไม่พร้อมใช้งาน"</item>
     <item msgid="8707481475312432575">"ปิด"</item>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index c929e45..ff8d84f 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Magdagdag ng higit pang widget"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pindutin nang matagal para i-customize ang mga widget"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"I-customize ang mga widget"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"I-edit ang widget"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Alisin"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Magdagdag ng widget"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Ipa-ring"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"I-vibrate"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"I-mute"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Mag-cast"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Hindi available dahil naka-mute ang ring"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. I-tap upang i-unmute."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. I-tap upang itakda na mag-vibrate. Maaaring i-mute ang mga serbisyo sa Accessibility."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. I-tap upang i-mute. Maaaring i-mute ang mga serbisyo sa Accessibility."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. I-tap upang itakda na mag-vibrate."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. I-tap upang i-mute."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Pagkontrol sa Ingay"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"I-tap para baguhin ang ringer mode"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"i-mute"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"i-unmute"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> ng <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Tingnan ang mga hakbang sa pangangalaga"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Tingnan ang mga hakbang sa pangangalaga"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Bunutin sa saksakan ang device"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Pagtatala"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Pagtatala, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Nagse-share ng audio"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Nagbo-broadcast"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Ihinto ang pag-broadcast ng <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Kung magbo-broadcast ka ng <xliff:g id="SWITCHAPP">%1$s</xliff:g> o babaguhin mo ang output, hihinto ang iyong kasalukuyang broadcast"</string>
diff --git a/packages/SystemUI/res/values-tl/tiles_states_strings.xml b/packages/SystemUI/res/values-tl/tiles_states_strings.xml
index 689c2a2..a12c010 100644
--- a/packages/SystemUI/res/values-tl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-tl/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Naka-off"</item>
     <item msgid="578444932039713369">"Naka-on"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Hindi available"</item>
     <item msgid="8707481475312432575">"Naka-off"</item>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 9407fbb..2cdc6e7 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Daha fazla widget ekle"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Widget\'ları özelleştirmek için uzun basın"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Widget\'ları özelleştir"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Widget\'ı düzenle"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Kaldır"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget ekle"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Zili çaldır"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Titreşim"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Sesi kapat"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Yayınla"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Zil sesi kapatıldığı için kullanılamıyor"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Sesi açmak için dokunun."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Titreşime ayarlamak için dokunun. Erişilebilirlik hizmetlerinin sesi kapatılabilir."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Sesi kapatmak için dokunun. Erişilebilirlik hizmetlerinin sesi kapatılabilir."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Titreşime ayarlamak için dokunun."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Sesi kapatmak için dokunun."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Gürültü Kontrolü"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Telefon zili modunu değiştirmek için dokunun"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"sesi  kapat"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"sesi aç"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Güç menüsü"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Sayfa <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Kilit ekranı"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Bakımla ilgili adımlara bakın"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Bakımla ilgili adımlara bakın"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Cihazınızın fişini çekin"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Not alma"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Not alma, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Ses paylaşılıyor"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Yayınlama"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasında anons durdurulsun mu?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> uygulamasında anons yapar veya çıkışı değiştirirseniz mevcut anonsunuz duraklatılır"</string>
diff --git a/packages/SystemUI/res/values-tr/tiles_states_strings.xml b/packages/SystemUI/res/values-tr/tiles_states_strings.xml
index a8c7f78..c6a8aec 100644
--- a/packages/SystemUI/res/values-tr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-tr/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Kapalı"</item>
     <item msgid="578444932039713369">"Açık"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Kullanılamıyor"</item>
     <item msgid="8707481475312432575">"Kapalı"</item>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index b7a4999..c89ae75 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Додати більше віджетів"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Утримуйте, щоб налаштувати віджети"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Налаштувати віджети"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Редагувати віджет"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Видалити"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додати віджет"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Дзвінок"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Вібросигнал"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Без звуку"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Трансляція"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Недоступно: звук дзвінків вимкнено"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Торкніться, щоб увімкнути звук."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Торкніться, щоб налаштувати вібросигнал. Спеціальні можливості може бути вимкнено."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Торкніться, щоб вимкнути звук. Спеціальні можливості може бути вимкнено."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Торкніться, щоб налаштувати вібросигнал."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Торкніться, щоб вимкнути звук."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Контроль шуму"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Торкніться, щоб змінити режим дзвінка"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"вимкнути звук"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"увімкнути звук"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Меню кнопки живлення"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Сторінка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Заблокований екран"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Переглянути запобіжні заходи"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Переглянути запобіжні заходи"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Від’єднайте пристрій"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Створення нотаток"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Створення нотаток, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Відтворюється аудіо"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Трансляція"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Зупинити трансляцію з додатка <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Якщо ви зміните додаток (<xliff:g id="SWITCHAPP">%1$s</xliff:g>) або аудіовихід, поточну трансляцію буде припинено"</string>
diff --git a/packages/SystemUI/res/values-uk/tiles_states_strings.xml b/packages/SystemUI/res/values-uk/tiles_states_strings.xml
index 4062f1b..a8e1ab8 100644
--- a/packages/SystemUI/res/values-uk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-uk/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Вимкнено"</item>
     <item msgid="578444932039713369">"Увімкнено"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Недоступно"</item>
     <item msgid="8707481475312432575">"Вимкнено"</item>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index f9155a0..3237f32 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -429,6 +429,7 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"مزید ویجٹس شامل کریں"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ویجٹس کو حسب ضرورت بنانے کے لیے لانگ پریس کریں"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ویجیٹس کو حسب ضرورت بنائیں"</string>
+    <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"غیر فعال ویجیٹ کے لئے ایپ آئیکن"</string>
     <string name="edit_widget" msgid="9030848101135393954">"ویجیٹ میں ترمیم کریں"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"ہٹائیں"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ویجیٹ شامل کریں"</string>
@@ -573,11 +574,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"رِنگ کریں"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"وائبریٹ"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"خاموش کریں"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"کاسٹ"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"دستیاب نہیں ہے کیونکہ رنگ خاموش ہے"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"‏‎%1$s۔ آواز چالو کرنے کیلئے تھپتھپائیں۔"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"‏‎%1$s۔ ارتعاش پر سیٹ کرنے کیلئے تھپتھپائیں۔ ایکسیسبیلٹی سروسز شاید خاموش ہوں۔"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏‎%1$s۔ خاموش کرنے کیلئے تھپتھپائیں۔ ایکسیسبیلٹی سروسز شاید خاموش ہوں۔"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‏‎%1$s۔ ارتعاش پر سیٹ کرنے کیلئے تھپتھپائیں۔"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‏‎%1$s۔ خاموش کرنے کیلئے تھپتھپائیں۔"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"شور کنٹرول"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"رنگر وضع تبدیل کرنے کیلئے تھپتھپائیں"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"خاموش کریں"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"غیر خاموش کریں"</string>
@@ -832,6 +836,8 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"پاور مینیو"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"صفحہ <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"مقفل اسکرین"</string>
+    <string name="finder_active" msgid="7907846989716941952">"پاور آف ہونے پر بھی آپ میرا آلہ ڈھونڈیں کے ساتھ اس فون کو تلاش کر سکتے ہیں"</string>
+    <string name="shutdown_progress" msgid="5464239146561542178">"بند ہو رہا ہے…"</string>
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"نگہداشت کے اقدامات ملاحظہ کریں"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"نگہداشت کے اقدامات ملاحظہ کریں"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"اپنے آلہ کو ان پلگ کریں"</string>
@@ -1186,6 +1192,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>، <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"نوٹ لکھنا"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"نوٹ لکھنا، <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"آڈیو کا اشتراک کرنا"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"نشریات"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> براڈکاسٹنگ روکیں؟"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"اگر آپ <xliff:g id="SWITCHAPP">%1$s</xliff:g> براڈکاسٹ کرتے ہیں یا آؤٹ پٹ کو تبدیل کرتے ہیں تو آپ کا موجودہ براڈکاسٹ رک جائے گا"</string>
diff --git a/packages/SystemUI/res/values-ur/tiles_states_strings.xml b/packages/SystemUI/res/values-ur/tiles_states_strings.xml
index bb27b9f..6d1e707 100644
--- a/packages/SystemUI/res/values-ur/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ur/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"آف ہے"</item>
     <item msgid="578444932039713369">"آن ہے"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"دستیاب نہیں ہے"</item>
     <item msgid="8707481475312432575">"آف ہے"</item>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 82b6b46..478fcdb 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Koʻproq vidjetlar qoʻshish"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Vidjetlarni sozlash uchun bosib turing"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Vidjetlarni moslashtirish"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Vidjetni tahrirlash"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Olib tashlash"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Vidjet kiritish"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Jiringlatish"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Tebranish"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Ovozsiz"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Translatsiya"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Jiringlash ovozsizligi uchun ishlamaydi"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Ovozini yoqish uchun ustiga bosing."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Tebranishni yoqish uchun ustiga bosing. Qulayliklar ishlamasligi mumkin."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ovozini o‘chirish uchun ustiga bosing. Qulayliklar ishlamasligi mumkin."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tebranishni yoqish uchun ustiga bosing."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ovozsiz qilish uchun ustiga bosing."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Shovqin boshqaruvi"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Jiringlagich rejimini oʻzgartirish uchun bosing"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ovozsiz qilish"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ovozni yoqish"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Quvvat menyusi"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>-sahifa, jami: <xliff:g id="ID_2">%2$d</xliff:g> ta sahifa"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Ekran qulfi"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Batafsil axborot"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Batafsil axborot"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Qurilmani uzing"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Qayd olish"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>: qayd olish"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Audio ulashuvi"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Signal uzatish"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga translatsiya toʻxtatilsinmi?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Agar <xliff:g id="SWITCHAPP">%1$s</xliff:g> ilovasiga translatsiya qilsangiz yoki ovoz chiqishini oʻzgartirsangiz, joriy translatsiya toʻxtab qoladi"</string>
diff --git a/packages/SystemUI/res/values-uz/tiles_states_strings.xml b/packages/SystemUI/res/values-uz/tiles_states_strings.xml
index bd5ee89..0558c4a 100644
--- a/packages/SystemUI/res/values-uz/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-uz/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Oʻchiq"</item>
     <item msgid="578444932039713369">"Yoniq"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Ishlamaydi"</item>
     <item msgid="8707481475312432575">"Oʻchiq"</item>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 2a8d4cd..7e8638b 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Thêm tiện ích khác"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nhấn và giữ để tuỳ chỉnh tiện ích"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Tuỳ chỉnh tiện ích"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Chỉnh sửa tiện ích"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Xoá"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Thêm tiện ích"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Đổ chuông"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Rung"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Tắt tiếng"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Truyền"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Không hoạt động vì chuông bị tắt"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Nhấn để bật tiếng."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Nhấn để đặt chế độ rung. Bạn có thể tắt tiếng dịch vụ trợ năng."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Nhấn để tắt tiếng. Bạn có thể tắt tiếng dịch vụ trợ năng."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Nhấn để đặt chế độ rung."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Nhấn để tắt tiếng."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Kiểm soát tiếng ồn"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Nhấn để thay đổi chế độ chuông"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"tắt tiếng"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"bật tiếng"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Trình đơn nguồn"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Trang <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Màn hình khóa"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Xem các bước chăm sóc"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Xem các bước chăm sóc"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Rút thiết bị ra"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Ghi chú"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Ghi chú, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Đang chia sẻ âm thanh"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Phát sóng"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Dừng phát <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Nếu bạn phát <xliff:g id="SWITCHAPP">%1$s</xliff:g> hoặc thay đổi đầu ra, phiên truyền phát hiện tại sẽ dừng"</string>
diff --git a/packages/SystemUI/res/values-vi/tiles_states_strings.xml b/packages/SystemUI/res/values-vi/tiles_states_strings.xml
index 201a45b..eee10d3 100644
--- a/packages/SystemUI/res/values-vi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-vi/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Đang tắt"</item>
     <item msgid="578444932039713369">"Đang bật"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Không hoạt động"</item>
     <item msgid="8707481475312432575">"Đang tắt"</item>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index ddef35f..2552138 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"添加更多微件"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"长按即可自定义微件"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"自定义微件"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"修改微件"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"添加微件"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"响铃"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"振动"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"静音"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"投屏"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"该功能无法使用,因为铃声被静音"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s。点按即可取消静音。"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s。点按即可设为振动,但可能会同时将无障碍服务设为静音。"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。点按即可设为静音,但可能会同时将无障碍服务设为静音。"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。点按即可设为振动。"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。点按即可设为静音。"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"噪声控制"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"点按即可更改振铃器模式"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"静音"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"取消静音"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"电源菜单"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"第 <xliff:g id="ID_1">%1$d</xliff:g> 页,共 <xliff:g id="ID_2">%2$d</xliff:g> 页"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"锁定屏幕"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"查看处理步骤"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看处理步骤"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"拔出设备"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>,<xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"记事"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"记事,<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"正在分享音频"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"正在广播"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"要停止广播“<xliff:g id="APP_NAME">%1$s</xliff:g>”的内容吗?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"如果广播“<xliff:g id="SWITCHAPP">%1$s</xliff:g>”的内容或更改输出来源,当前的广播就会停止"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
index 3ab2d7a..82ab671 100644
--- a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"已关闭"</item>
     <item msgid="578444932039713369">"已开启"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"不可用"</item>
     <item msgid="8707481475312432575">"已关闭"</item>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index dbf2cc0..5941dad 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"新增更多小工具"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長按即可自訂小工具"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"自訂小工具"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"編輯小工具"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"新增小工具"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"鈴聲"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"震動"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"靜音"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"投放"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"鈴聲已設定為靜音,因此無法使用"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s。輕按即可取消靜音。"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s。輕按即可設為震動。無障礙功能服務可能已經設為靜音。"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。輕按即可設為靜音。無障礙功能服務可能已經設為靜音。"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。輕按即可設為震動。"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。輕按即可設為靜音。"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"噪音控制"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"輕按即可變更響鈴模式"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"靜音"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"取消靜音"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"電源選單"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁 (共 <xliff:g id="ID_2">%2$d</xliff:g> 頁)"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"螢幕鎖定"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"查看保養步驟"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看保養步驟"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"拔除裝置"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>,<xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"做筆記"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"做筆記,<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"正在分享音訊"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"廣播"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"要停止廣播「<xliff:g id="APP_NAME">%1$s</xliff:g>」的內容嗎?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"如要廣播「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容或變更輸出來源,系統就會停止廣播目前的內容"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
index 89d6628..6bac275 100644
--- a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"已關閉"</item>
     <item msgid="578444932039713369">"已開啟"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"無法使用"</item>
     <item msgid="8707481475312432575">"已關閉"</item>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index d92de1c..c46d831 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"新增更多小工具"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長按即可自訂小工具"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"自訂小工具"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"編輯小工具"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"新增小工具"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"鈴聲"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"震動"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"靜音"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"投放"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"鈴聲已設為靜音,因此無法使用"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s。輕觸即可取消靜音。"</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s。輕觸即可設為震動,但系統可能會將無障礙服務一併設為靜音。"</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。輕觸即可設為靜音,但系統可能會將無障礙服務一併設為靜音。"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。輕觸即可設為震動。"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。輕觸即可設為靜音。"</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"噪音控制"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"輕觸即可變更鈴聲模式"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"靜音"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"取消靜音"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"電源鍵選單"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁,共 <xliff:g id="ID_2">%2$d</xliff:g> 頁"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"鎖定畫面"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"查看處理步驟"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看處理步驟"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"拔除裝置"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>,<xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"做筆記"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"做筆記,<xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"分享音訊"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"廣播"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"要停止播送「<xliff:g id="APP_NAME">%1$s</xliff:g>」的內容嗎?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"如果播送「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容或變更輸出來源,系統就會停止播送目前的內容"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
index a046e33..5794bf1 100644
--- a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"已關閉"</item>
     <item msgid="578444932039713369">"已開啟"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"無法使用"</item>
     <item msgid="8707481475312432575">"已關閉"</item>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 9cd7082..0bbac05 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -429,6 +429,8 @@
     <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Engeza amawijethi engeziwe"</string>
     <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Cindezela isikhathi eside ukuze wenze ngokwezifiso amawijethi"</string>
     <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Yenza ngokwezifiso amawijethi"</string>
+    <!-- no translation found for icon_description_for_disabled_widget (4693151565003206943) -->
+    <skip />
     <string name="edit_widget" msgid="9030848101135393954">"Hlela amawijethi"</string>
     <string name="button_to_remove_widget" msgid="3948204829181214098">"Susa"</string>
     <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Engeza iwijethi"</string>
@@ -573,11 +575,14 @@
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Khalisa"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Dlidlizela"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Thulisa"</string>
+    <string name="media_device_cast" msgid="4786241789687569892">"Sakaza"</string>
+    <string name="stream_notification_unavailable" msgid="4313854556205836435">"Ayitholakali ngoba ukukhala kuthulisiwe"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Thepha ukuze ususe ukuthula."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Thepha ukuze usethe ukudlidliza. Amasevisi okufinyelela angathuliswa."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Thepha ukuze uthulise. Amasevisi okufinyelela angathuliswa."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Thepha ukuze usethele ekudlidlizeni."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Thepha ukuze uthulise."</string>
+    <string name="volume_panel_noise_control_title" msgid="7413949943872304474">"Ulawulo Lomsindo"</string>
     <string name="volume_ringer_change" msgid="3574969197796055532">"Thepha ukuze ushintshe imodi yokukhala"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"thulisa"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"susa ukuthula"</string>
@@ -832,6 +837,10 @@
     <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Imenyu yamandla"</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Ikhasi <xliff:g id="ID_1">%1$d</xliff:g> kwangu-<xliff:g id="ID_2">%2$d</xliff:g>"</string>
     <string name="tuner_lock_screen" msgid="2267383813241144544">"Khiya isikrini"</string>
+    <!-- no translation found for finder_active (7907846989716941952) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (5464239146561542178) -->
+    <skip />
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Bona izinyathelo zokunakekelwa"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Bona izinyathelo zokunakekelwa"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Khipha idivayisi yakho"</string>
@@ -1186,6 +1195,7 @@
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="note_task_button_label" msgid="230135078402003532">"Ukuthatha amanothi"</string>
     <string name="note_task_shortcut_long_label" msgid="7729325091147319409">"Ukuthatha amanothi, <xliff:g id="NOTE_TAKING_APP">%1$s</xliff:g>"</string>
+    <string name="audio_sharing_description" msgid="8849060142768870004">"Yabelana ngomsindo"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Ukusakaza"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Misa ukusakaza i-<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Uma usakaza i-<xliff:g id="SWITCHAPP">%1$s</xliff:g> noma ushintsha okuphumayo, ukusakaza kwakho kwamanje kuzoma"</string>
diff --git a/packages/SystemUI/res/values-zu/tiles_states_strings.xml b/packages/SystemUI/res/values-zu/tiles_states_strings.xml
index e35840b..8c7b652 100644
--- a/packages/SystemUI/res/values-zu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zu/tiles_states_strings.xml
@@ -126,6 +126,9 @@
     <item msgid="8259411607272330225">"Valiwe"</item>
     <item msgid="578444932039713369">"Vuliwe"</item>
   </string-array>
+    <!-- no translation found for tile_states_record_issue:0 (1727196795383575383) -->
+    <!-- no translation found for tile_states_record_issue:1 (9061144428113385092) -->
+    <!-- no translation found for tile_states_record_issue:2 (2984256114867200368) -->
   <string-array name="tile_states_reverse">
     <item msgid="3574611556622963971">"Akutholakali"</item>
     <item msgid="8707481475312432575">"Valiwe"</item>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index beaa708..e181d07 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -101,7 +101,7 @@
 
     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
     <string name="quick_settings_tiles_stock" translatable="false">
-        internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction,dream,font_scaling
+        internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction,dream,font_scaling,record_issue
     </string>
 
     <!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5436642..b7eff38 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -164,6 +164,9 @@
     so the width of the icon should be 13.0sp * (12.0 / 20.0) -->
     <dimen name="status_bar_battery_icon_width">7.8sp</dimen>
 
+    <dimen name="status_bar_battery_unified_icon_width">24sp</dimen>
+    <dimen name="status_bar_battery_unified_icon_height">14sp</dimen>
+
     <!-- The battery icon is 13sp tall, but the other system icons are 15sp tall (see
          @*android:dimen/status_bar_system_icon_size) with some top and bottom padding embedded in
          the drawables themselves. So, the battery icon may need an extra 1dp of spacing so that its
@@ -199,6 +202,7 @@
     <!-- Size of the view displaying the mobile signal icon in the status bar. This value should
         match the core/status_bar_system_icon_size and change to sp unit -->
     <dimen name="status_bar_mobile_signal_size">15sp</dimen>
+    <dimen name="status_bar_mobile_signal_size_updated">14sp</dimen>
     <!-- Size of the view displaying the mobile signal icon in the status bar. This value should
         match the viewport height of mobile signal drawables such as ic_lte_mobiledata -->
     <dimen name="status_bar_mobile_type_size">16sp</dimen>
@@ -898,8 +902,8 @@
     <dimen name="communal_enforced_rounded_corner_max_radius">16dp</dimen>
 
     <!-- Width and height used to filter widgets displayed in the communal widget picker -->
-    <dimen name="communal_widget_picker_desired_width">464dp</dimen>
-    <dimen name="communal_widget_picker_desired_height">307dp</dimen>
+    <dimen name="communal_widget_picker_desired_width">424dp</dimen>
+    <dimen name="communal_widget_picker_desired_height">282dp</dimen>
 
     <!-- The width/height of the unlock icon view on keyguard. -->
     <dimen name="keyguard_lock_height">42dp</dimen>
@@ -1518,6 +1522,12 @@
     <!-- GLANCEABLE_HUB -> LOCKSCREEN transition: Amount to shift lockscreen content on entering -->
     <dimen name="hub_to_lockscreen_transition_lockscreen_translation_x">824dp</dimen>
 
+    <!-- DREAMING -> GLANCEABLE_HUB transition: Amount to shift dream overlay on entering -->
+    <dimen name="dreaming_to_hub_transition_dream_overlay_translation_x">-824dp</dimen>
+
+    <!-- GLANCEABLE_HUB -> DREAMING transition: Amount to shift dream overlay on entering -->
+    <dimen name="hub_to_dreaming_transition_dream_overlay_translation_x">824dp</dimen>
+
     <!-- Distance that the full shade transition takes in order for media to fully transition to
          the shade -->
     <dimen name="lockscreen_shade_media_transition_distance">120dp</dimen>
@@ -1736,12 +1746,18 @@
     <dimen name="communal_grid_height">630dp</dimen>
     <!-- Number of columns for each communal card -->
     <integer name="communal_grid_columns_per_card">6</integer>
-    <!-- Width of area on right edge of screen in which swipes will open the communal hub -->
-    <dimen name="communal_right_edge_swipe_region_width">16dp</dimen>
+
+    <!-- The width of the swipe target to initiate opening or closing communal hub. -->
+    <dimen name="communal_gesture_initiation_width">68dp</dimen>
+
+    <!-- TODO(b/322549765): unify with communal_gesture_initiation_width -->
+    <!-- Width of area on right edge of screen in which swipes will open the communal hub when on
+    the lockscreen -->
+    <dimen name="communal_right_edge_swipe_region_width">40dp</dimen>
     <!-- Height of area at top of communal hub where swipes should open the notification shade -->
-    <dimen name="communal_top_edge_swipe_region_height">32dp</dimen>
+    <dimen name="communal_top_edge_swipe_region_height">68dp</dimen>
     <!-- Height of area at bottom of communal hub where swipes should open the bouncer -->
-    <dimen name="communal_bottom_edge_swipe_region_height">32dp</dimen>
+    <dimen name="communal_bottom_edge_swipe_region_height">68dp</dimen>
 
     <dimen name="drag_and_drop_icon_size">70dp</dimen>
 
@@ -1813,9 +1829,6 @@
     <dimen name="dream_overlay_complication_smartspace_padding">24dp</dimen>
     <dimen name="dream_overlay_complication_smartspace_max_width">408dp</dimen>
 
-    <!-- The width of the swipe target to initiate opening communal hub over dreams. -->
-    <dimen name="communal_gesture_initiation_width">48dp</dimen>
-
     <!-- The position of the end guide, which dream overlay complications can align their start with
          if their end is aligned with the parent end. Represented as the percentage over from the
          start of the parent container. -->
@@ -1861,7 +1874,6 @@
     <dimen name="dream_overlay_y_offset">80dp</dimen>
     <dimen name="dream_overlay_entry_y_offset">40dp</dimen>
     <dimen name="dream_overlay_exit_y_offset">40dp</dimen>
-    <dimen name="dream_overlay_exit_x_offset">824dp</dimen>
 
     <dimen name="status_view_margin_horizontal">0dp</dimen>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4263d94..b713417 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -34,6 +34,10 @@
         remaining [CHAR LIMIT=none]-->
     <string name="battery_low_percent_format"><xliff:g id="percentage">%s</xliff:g> remaining</string>
 
+    <!-- SVG path description for the battery frame of the unified battery drawable
+    (BatteryLayersDrawable.kt). Drawn on a 24x14 canvas. Not suitable outside in any other context -->
+    <string name="battery_unified_frame_path_string" translatable="false">M2.75,3C2.75,1.757 3.757,0.75 5,0.75H20C21.795,0.75 23.25,2.205 23.25,4V10C23.25,11.795 21.795,13.25 20,13.25H5C3.757,13.25 2.75,12.243 2.75,11V3Z </string>
+
     <!-- A message that appears when the battery remaining estimate is low in a dialog.  This is
     appended to the subtitle of the low battery alert.  "percentage" is the percentage of battery
     remaining. "time" is the amount of time remaining before the phone runs out of battery [CHAR LIMIT=none]-->
@@ -1114,6 +1118,8 @@
     <string name="popup_on_dismiss_cta_tile_text">Long press to customize widgets</string>
     <!-- Text for the button to configure widgets after long press. [CHAR LIMIT=50] -->
     <string name="button_to_configure_widgets_text">Customize widgets</string>
+    <!-- Description for the App icon of disabled widget. [CHAR LIMIT=NONE] -->
+    <string name="icon_description_for_disabled_widget">App icon for disabled widget</string>
     <!-- Label for the button which configures widgets [CHAR LIMIT=NONE] -->
     <string name="edit_widget">Edit widget</string>
     <!-- Description for the button that removes a widget on click. [CHAR LIMIT=50] -->
@@ -2236,6 +2242,11 @@
     <!-- Tuner string -->
     <!-- Tuner string -->
 
+    <!-- Message shown during shutdown when Find My Device with Dead Battery Finder is active  [CHAR LIMIT=300] -->
+    <string name="finder_active">You can locate this phone with Find My Device even when powered off</string>
+    <!-- Shutdown Progress Dialog. This is shown if the user chooses to power off the phone. [CHAR LIMIT=60] -->
+    <string name="shutdown_progress">Shutting down\u2026</string>
+
     <!-- Text help link for care instructions for overheating devices [CHAR LIMIT=40] -->
     <string name="thermal_shutdown_dialog_help_text">See care steps</string>
     <!-- URL for care instructions for overheating devices -->
@@ -3243,6 +3254,12 @@
     <!-- Text for education page content description for unfolded animation. [CHAR_LIMIT=NONE] -->
     <string name="rear_display_accessibility_unfolded_animation">Foldable device being flipped around</string>
 
+    <!-- QuickSettings: Additional label for the auto-rotation quicksettings tile indicating that the setting corresponds to the folded posture for a foldable device [CHAR LIMIT=32] -->
+    <string name="quick_settings_rotation_posture_folded">folded</string>
+    <!-- QuickSettings: Additional label for the auto-rotation quicksettings tile indicating that the setting corresponds to the unfolded posture for a foldable device [CHAR LIMIT=32] -->
+    <string name="quick_settings_rotation_posture_unfolded">unfolded</string>
+    <!-- QuickSettings: template for rotation tile foldable secondary label [CHAR LIMIT=64] !-->
+    <string name="rotation_tile_with_posture_secondary_label_template">%1$s / %2$s</string>
     <!-- Title for notification of low stylus battery with percentage. "percentage" is
         the value of the battery capacity remaining [CHAR LIMIT=none]-->
     <string name="stylus_battery_low_percentage"><xliff:g id="percentage" example="16%">%s</xliff:g> battery remaining</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 617eadb..ce08ca3 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -1581,4 +1581,8 @@
     <style name="Theme.PrivacyDialog" parent="@style/Theme.SystemUI.Dialog">
         <item name="android:colorBackground">?androidprv:attr/materialColorSurfaceContainer</item>
     </style>
+
+    <style name="Theme.SystemUI.Dialog.StickyKeys" parent="@style/Theme.SystemUI.Dialog">
+        <item name="android:colorBackground">@color/transparent</item>
+    </style>
 </resources>
diff --git a/packages/SystemUI/res/values/tiles_states_strings.xml b/packages/SystemUI/res/values/tiles_states_strings.xml
index 7020d54..9036a35 100644
--- a/packages/SystemUI/res/values/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values/tiles_states_strings.xml
@@ -222,6 +222,16 @@
         <item>On</item>
     </string-array>
 
+    <!-- State names for record_issue tile: unavailable, off, on.
+         This subtitle is shown when the tile is in that particular state but does not set its own
+         subtitle, so some of these may never appear on screen. They should still be translated as
+         if they could appear. [CHAR LIMIT=32] -->
+    <string-array name="tile_states_record_issue">
+        <item>Unavailable</item>
+        <item>Off</item>
+        <item>On</item>
+    </string-array>
+
     <!-- State names for reverse (charging) tile: unavailable, off, on.
          This subtitle is shown when the tile is in that particular state but does not set its own
          subtitle, so some of these may never appear on screen. They should still be translated as
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 10393cf..ca63483 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -196,7 +196,7 @@
             final RecentsAnimationListener animationHandler, final Consumer<Boolean> resultCallback,
             Handler resultCallbackHandler) {
         boolean result = startRecentsActivity(intent, eventTime, animationHandler);
-        if (resultCallback != null) {
+        if (resultCallback != null && resultCallbackHandler != null) {
             resultCallbackHandler.post(new Runnable() {
                 @Override
                 public void run() {
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
index 1cfa816..b9b8fbe 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
@@ -17,9 +17,9 @@
 package com.android.keyguard;
 
 import static com.android.keyguard.logging.CarrierTextManagerLogger.REASON_ACTIVE_DATA_SUB_CHANGED;
-import static com.android.keyguard.logging.CarrierTextManagerLogger.REASON_ON_SIM_STATE_CHANGED;
 import static com.android.keyguard.logging.CarrierTextManagerLogger.REASON_ON_TELEPHONY_CAPABLE;
 import static com.android.keyguard.logging.CarrierTextManagerLogger.REASON_REFRESH_CARRIER_INFO;
+import static com.android.keyguard.logging.CarrierTextManagerLogger.REASON_SIM_ERROR_STATE_CHANGED;
 
 import android.content.Context;
 import android.content.Intent;
@@ -123,12 +123,15 @@
                 return;
             }
 
-            mLogger.logUpdateCarrierTextForReason(REASON_ON_SIM_STATE_CHANGED);
+
+            mLogger.logSimStateChangedCallback(subId, slotId, simState);
             if (getStatusForIccState(simState) == CarrierTextManager.StatusMode.SimIoError) {
                 mSimErrorState[slotId] = true;
+                mLogger.logUpdateCarrierTextForReason(REASON_SIM_ERROR_STATE_CHANGED);
                 updateCarrierText();
             } else if (mSimErrorState[slotId]) {
                 mSimErrorState[slotId] = false;
+                mLogger.logUpdateCarrierTextForReason(REASON_SIM_ERROR_STATE_CHANGED);
                 updateCarrierText();
             }
         }
@@ -206,6 +209,9 @@
                 // This will set/remove the listeners appropriately. Note that it will never double
                 // add the listeners.
                 handleSetListening(mCarrierTextCallback);
+                mainExecutor.execute(() -> {
+                    mKeyguardUpdateMonitor.registerCallback(mCallback);
+                });
             }
         });
     }
@@ -273,7 +279,6 @@
             if (mNetworkSupported.get()) {
                 // Keyguard update monitor expects callbacks from main thread
                 mMainExecutor.execute(() -> {
-                    mKeyguardUpdateMonitor.registerCallback(mCallback);
                     mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
                 });
                 mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener);
@@ -286,7 +291,6 @@
         } else {
             mCarrierTextCallback = null;
             mMainExecutor.execute(() -> {
-                mKeyguardUpdateMonitor.removeCallback(mCallback);
                 mWakefulnessLifecycle.removeObserver(mWakefulnessObserver);
             });
             mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mPhoneStateListener);
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 05e07a7..f28d405 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -15,8 +15,6 @@
  */
 package com.android.keyguard
 
-import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
-import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
 import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
@@ -43,14 +41,16 @@
 import com.android.systemui.flags.Flags.REGION_SAMPLING
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
+import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.log.core.Logger
+import com.android.systemui.plugins.clocks.AlarmData
 import com.android.systemui.plugins.clocks.ClockController
 import com.android.systemui.plugins.clocks.ClockFaceController
 import com.android.systemui.plugins.clocks.ClockMessageBuffers
 import com.android.systemui.plugins.clocks.ClockTickRate
-import com.android.systemui.plugins.clocks.AlarmData
 import com.android.systemui.plugins.clocks.WeatherData
 import com.android.systemui.plugins.clocks.ZenData
 import com.android.systemui.plugins.clocks.ZenData.ZenMode
@@ -61,16 +61,18 @@
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.ZenModeController
 import com.android.systemui.util.concurrency.DelayableExecutor
+import java.util.Locale
+import java.util.TimeZone
+import java.util.concurrent.Executor
+import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.DisposableHandle
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.launch
-import java.util.Locale
-import java.util.TimeZone
-import java.util.concurrent.Executor
-import javax.inject.Inject
 
 /**
  * Controller for a Clock provided by the registry and used on the keyguard. Instantiated by
@@ -93,11 +95,13 @@
     private val featureFlags: FeatureFlagsClassic,
     private val zenModeController: ZenModeController,
 ) {
-    var loggers = listOf(
-        clockBuffers.infraMessageBuffer,
-        clockBuffers.smallClockMessageBuffer,
-        clockBuffers.largeClockMessageBuffer
-    ).map { Logger(it, TAG) }
+    var loggers =
+        listOf(
+                clockBuffers.infraMessageBuffer,
+                clockBuffers.smallClockMessageBuffer,
+                clockBuffers.largeClockMessageBuffer
+            )
+            .map { Logger(it, TAG) }
 
     var clock: ClockController? = null
         get() = field
@@ -108,11 +112,12 @@
         }
 
     private fun disconnectClock(clock: ClockController?) {
-        if (clock == null) { return; }
+        if (clock == null) {
+            return
+        }
         smallClockOnAttachStateChangeListener?.let {
             clock.smallClock.view.removeOnAttachStateChangeListener(it)
-            smallClockFrame?.viewTreeObserver
-                    ?.removeOnGlobalLayoutListener(onGlobalLayoutListener)
+            smallClockFrame?.viewTreeObserver?.removeOnGlobalLayoutListener(onGlobalLayoutListener)
         }
         largeClockOnAttachStateChangeListener?.let {
             clock.largeClock.view.removeOnAttachStateChangeListener(it)
@@ -120,7 +125,9 @@
     }
 
     private fun connectClock(clock: ClockController?) {
-        if (clock == null) { return; }
+        if (clock == null) {
+            return
+        }
         val clockStr = clock.toString()
         loggers.forEach { it.d({ "New Clock: $str1" }) { str1 = clockStr } }
 
@@ -129,23 +136,27 @@
         if (!regionSamplingEnabled) {
             updateColors()
         } else {
-            smallRegionSampler = createRegionSampler(
-                clock.smallClock.view,
-                mainExecutor,
-                bgExecutor,
-                regionSamplingEnabled,
-                isLockscreen = true,
-                ::updateColors
-            ).apply { startRegionSampler() }
+            smallRegionSampler =
+                createRegionSampler(
+                        clock.smallClock.view,
+                        mainExecutor,
+                        bgExecutor,
+                        regionSamplingEnabled,
+                        isLockscreen = true,
+                        ::updateColors
+                    )
+                    .apply { startRegionSampler() }
 
-            largeRegionSampler = createRegionSampler(
-                clock.largeClock.view,
-                mainExecutor,
-                bgExecutor,
-                regionSamplingEnabled,
-                isLockscreen = true,
-                ::updateColors
-            ).apply { startRegionSampler() }
+            largeRegionSampler =
+                createRegionSampler(
+                        clock.largeClock.view,
+                        mainExecutor,
+                        bgExecutor,
+                        regionSamplingEnabled,
+                        isLockscreen = true,
+                        ::updateColors
+                    )
+                    .apply { startRegionSampler() }
 
             updateColors()
         }
@@ -158,49 +169,49 @@
             }
             clock.events.onWeatherDataChanged(it)
         }
-        zenData?.let {
-            clock.events.onZenDataChanged(it)
-        }
-        alarmData?.let {
-            clock.events.onAlarmDataChanged(it)
-        }
+        zenData?.let { clock.events.onZenDataChanged(it) }
+        alarmData?.let { clock.events.onAlarmDataChanged(it) }
 
-        smallClockOnAttachStateChangeListener = object : OnAttachStateChangeListener {
-            var pastVisibility: Int? = null
-            override fun onViewAttachedToWindow(view: View) {
-                clock.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
-                // Match the asing for view.parent's layout classes.
-                smallClockFrame = (view.parent as ViewGroup)?.also { frame ->
-                    pastVisibility = frame.visibility
-                    onGlobalLayoutListener = OnGlobalLayoutListener {
-                        val currentVisibility = frame.visibility
-                        if (pastVisibility != currentVisibility) {
-                            pastVisibility = currentVisibility
-                            // when small clock is visible,
-                            // recalculate bounds and sample
-                            if (currentVisibility == View.VISIBLE) {
-                                smallRegionSampler?.stopRegionSampler()
-                                smallRegionSampler?.startRegionSampler()
+        smallClockOnAttachStateChangeListener =
+            object : OnAttachStateChangeListener {
+                var pastVisibility: Int? = null
+                override fun onViewAttachedToWindow(view: View) {
+                    clock.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
+                    // Match the asing for view.parent's layout classes.
+                    smallClockFrame =
+                        (view.parent as ViewGroup)?.also { frame ->
+                            pastVisibility = frame.visibility
+                            onGlobalLayoutListener = OnGlobalLayoutListener {
+                                val currentVisibility = frame.visibility
+                                if (pastVisibility != currentVisibility) {
+                                    pastVisibility = currentVisibility
+                                    // when small clock is visible,
+                                    // recalculate bounds and sample
+                                    if (currentVisibility == View.VISIBLE) {
+                                        smallRegionSampler?.stopRegionSampler()
+                                        smallRegionSampler?.startRegionSampler()
+                                    }
+                                }
                             }
+                            frame.viewTreeObserver.addOnGlobalLayoutListener(onGlobalLayoutListener)
                         }
-                    }
-                    frame.viewTreeObserver.addOnGlobalLayoutListener(onGlobalLayoutListener)
+                }
+
+                override fun onViewDetachedFromWindow(p0: View) {
+                    smallClockFrame
+                        ?.viewTreeObserver
+                        ?.removeOnGlobalLayoutListener(onGlobalLayoutListener)
                 }
             }
-
-            override fun onViewDetachedFromWindow(p0: View) {
-                smallClockFrame?.viewTreeObserver
-                        ?.removeOnGlobalLayoutListener(onGlobalLayoutListener)
-            }
-        }
         clock.smallClock.view.addOnAttachStateChangeListener(smallClockOnAttachStateChangeListener)
 
-        largeClockOnAttachStateChangeListener = object : OnAttachStateChangeListener {
-            override fun onViewAttachedToWindow(p0: View) {
-                clock.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
+        largeClockOnAttachStateChangeListener =
+            object : OnAttachStateChangeListener {
+                override fun onViewAttachedToWindow(p0: View) {
+                    clock.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
+                }
+                override fun onViewDetachedFromWindow(p0: View) {}
             }
-            override fun onViewDetachedFromWindow(p0: View) {}
-        }
         clock.largeClock.view.addOnAttachStateChangeListener(largeClockOnAttachStateChangeListener)
     }
 
@@ -263,7 +274,9 @@
             bgExecutor,
             regionSamplingEnabled,
             isLockscreen,
-        ) { updateColors() }
+        ) {
+            updateColors()
+        }
     }
 
     var smallRegionSampler: RegionSampler? = null
@@ -364,35 +377,36 @@
             }
         }
 
-    private val zenModeCallback = object : ZenModeController.Callback {
-        override fun onZenChanged(zen: Int) {
-            var mode = ZenMode.fromInt(zen)
-            if (mode == null) {
-                Log.e(TAG, "Failed to get zen mode from int: $zen")
-                return
-            }
-
-            zenData = ZenData(
-                mode,
-                if (mode == ZenMode.OFF) SysuiR.string::dnd_is_off.name
-                    else SysuiR.string::dnd_is_on.name
-            ).also { data ->
-                mainExecutor.execute {
-                    clock?.run { events.onZenDataChanged(data) }
+    private val zenModeCallback =
+        object : ZenModeController.Callback {
+            override fun onZenChanged(zen: Int) {
+                var mode = ZenMode.fromInt(zen)
+                if (mode == null) {
+                    Log.e(TAG, "Failed to get zen mode from int: $zen")
+                    return
                 }
-            }
-        }
 
-        override fun onNextAlarmChanged() {
-            val nextAlarmMillis = zenModeController.getNextAlarm()
-            alarmData = AlarmData(
-                if (nextAlarmMillis > 0) nextAlarmMillis else null,
-                SysuiR.string::status_bar_alarm.name
-            ).also { data ->
-                clock?.run { events.onAlarmDataChanged(data) }
+                zenData =
+                    ZenData(
+                            mode,
+                            if (mode == ZenMode.OFF) SysuiR.string::dnd_is_off.name
+                            else SysuiR.string::dnd_is_on.name
+                        )
+                        .also { data ->
+                            mainExecutor.execute { clock?.run { events.onZenDataChanged(data) } }
+                        }
+            }
+
+            override fun onNextAlarmChanged() {
+                val nextAlarmMillis = zenModeController.getNextAlarm()
+                alarmData =
+                    AlarmData(
+                            if (nextAlarmMillis > 0) nextAlarmMillis else null,
+                            SysuiR.string::status_bar_alarm.name
+                        )
+                        .also { data -> clock?.run { events.onAlarmDataChanged(data) } }
             }
         }
-    }
 
     fun registerListeners(parent: View) {
         if (isRegistered) {
@@ -445,12 +459,15 @@
         largeRegionSampler?.stopRegionSampler()
         smallTimeListener?.stop()
         largeTimeListener?.stop()
-        clock?.smallClock?.view
-                ?.removeOnAttachStateChangeListener(smallClockOnAttachStateChangeListener)
-        smallClockFrame?.viewTreeObserver
-                ?.removeOnGlobalLayoutListener(onGlobalLayoutListener)
-        clock?.largeClock?.view
-                ?.removeOnAttachStateChangeListener(largeClockOnAttachStateChangeListener)
+        clock
+            ?.smallClock
+            ?.view
+            ?.removeOnAttachStateChangeListener(smallClockOnAttachStateChangeListener)
+        smallClockFrame?.viewTreeObserver?.removeOnGlobalLayoutListener(onGlobalLayoutListener)
+        clock
+            ?.largeClock
+            ?.view
+            ?.removeOnAttachStateChangeListener(largeClockOnAttachStateChangeListener)
     }
 
     /**
@@ -474,12 +491,10 @@
         largeTimeListener = null
 
         clock?.let {
-            smallTimeListener = TimeListener(it.smallClock, mainExecutor).apply {
-                update(shouldTimeListenerRun)
-            }
-            largeTimeListener = TimeListener(it.largeClock, mainExecutor).apply {
-                update(shouldTimeListenerRun)
-            }
+            smallTimeListener =
+                TimeListener(it.smallClock, mainExecutor).apply { update(shouldTimeListenerRun) }
+            largeTimeListener =
+                TimeListener(it.largeClock, mainExecutor).apply { update(shouldTimeListenerRun) }
         }
     }
 
@@ -518,7 +533,13 @@
     @VisibleForTesting
     internal fun listenForDozeAmountTransition(scope: CoroutineScope): Job {
         return scope.launch {
-            keyguardTransitionInteractor.dozeAmountTransition.collect { handleDoze(it.value) }
+            merge(
+                    keyguardTransitionInteractor.aodToLockscreenTransition.map { step ->
+                        step.copy(value = 1f - step.value)
+                    },
+                    keyguardTransitionInteractor.lockscreenToAodTransition,
+                )
+                .collect { handleDoze(it.value) }
         }
     }
 
@@ -528,7 +549,8 @@
     @VisibleForTesting
     internal fun listenForAnyStateToAodTransition(scope: CoroutineScope): Job {
         return scope.launch {
-            keyguardTransitionInteractor.transitionStepsToState(AOD)
+            keyguardTransitionInteractor
+                .transitionStepsToState(AOD)
                 .filter { it.transitionState == TransitionState.STARTED }
                 .filter { it.from != LOCKSCREEN }
                 .collect { handleDoze(1f) }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
index fc4e122..4c3f623 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
@@ -103,7 +103,7 @@
     public static boolean isEsimLocked(Context context, int subId) {
         EuiccManager euiccManager =
                 (EuiccManager) context.getSystemService(Context.EUICC_SERVICE);
-        if (!euiccManager.isEnabled()) {
+        if (euiccManager == null || !euiccManager.isEnabled()) {
             return false;
         }
         SubscriptionInfo sub = SubscriptionManager.from(context).getActiveSubscriptionInfo(subId);
@@ -118,6 +118,10 @@
 
     @Override
     public void onClick(View v) {
+        if (mEuiccManager == null) {
+            Log.e(TAG, "EuiccManager not present");
+            return;
+        }
         SubscriptionInfo sub = SubscriptionManager.from(mContext)
                 .getActiveSubscriptionInfo(mSubscriptionId);
         if (sub == null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
index 363dd01..f528ec8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
@@ -18,11 +18,16 @@
 
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
+import android.hardware.biometrics.BiometricSourceType;
+import android.os.SystemClock;
 import android.text.Editable;
 import android.text.TextUtils;
 import android.text.TextWatcher;
+import android.util.Log;
+import android.util.Pair;
 import android.view.View;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -40,6 +45,16 @@
 public class KeyguardMessageAreaController<T extends KeyguardMessageArea>
         extends ViewController<T> {
     /**
+     * Pair representing:
+     *   first - BiometricSource the currently displayed message is associated with.
+     *   second - Timestamp the biometric message came in uptimeMillis.
+     * This Pair can be null if the message is not associated with a biometric.
+     */
+    @Nullable
+    private Pair<BiometricSourceType, Long> mMessageBiometricSource = null;
+    private static final Long SKIP_SHOWING_FACE_MESSAGE_AFTER_FP_MESSAGE_MS = 3500L;
+
+    /**
      * Delay before speaking an accessibility announcement. Used to prevent
      * lift-to-type from interrupting itself.
      */
@@ -149,12 +164,42 @@
      * Sets a message to the underlying text view.
      */
     public void setMessage(CharSequence s, boolean animate) {
+        setMessage(s, animate, null);
+    }
+
+    /**
+     * Sets a message to the underlying text view.
+     */
+    public void setMessage(CharSequence s, BiometricSourceType biometricSourceType) {
+        setMessage(s, true, biometricSourceType);
+    }
+
+    private void setMessage(
+            CharSequence s,
+            boolean animate,
+            BiometricSourceType biometricSourceType) {
+        final long uptimeMillis = SystemClock.uptimeMillis();
+        if (skipShowingFaceMessage(biometricSourceType, uptimeMillis)) {
+            Log.d("KeyguardMessageAreaController", "Skip showing face message \"" + s + "\"");
+            return;
+        }
+        mMessageBiometricSource =  new Pair<>(biometricSourceType, uptimeMillis);
         if (mView.isDisabled()) {
             return;
         }
         mView.setMessage(s, animate);
     }
 
+    private boolean skipShowingFaceMessage(
+            BiometricSourceType biometricSourceType, Long currentUptimeMillis
+    ) {
+        return mMessageBiometricSource != null
+                && biometricSourceType == BiometricSourceType.FACE
+                && mMessageBiometricSource.first == BiometricSourceType.FINGERPRINT
+                && (currentUptimeMillis - mMessageBiometricSource.second)
+                    < SKIP_SHOWING_FACE_MESSAGE_AFTER_FP_MESSAGE_MS;
+    }
+
     public void setMessage(int resId) {
         String message = resId != 0 ? mView.getResources().getString(resId) : null;
         setMessage(message);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
index 7473e0c6..490ad5c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
@@ -86,8 +86,9 @@
     };
 
     private final View.OnKeyListener mKeyListener = (v, keyCode, keyEvent) -> {
+        // Ignore SPACE as a confirm key to allow the space character within passwords.
         final boolean isKeyboardEnterKey = keyEvent != null
-                && KeyEvent.isConfirmKey(keyCode)
+                && KeyEvent.isConfirmKey(keyCode) && keyCode != KeyEvent.KEYCODE_SPACE
                 && keyEvent.getAction() == KeyEvent.ACTION_UP;
         if (isKeyboardEnterKey) {
             verifyPasswordAndUnlock();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 38c2829e..8c51a4e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -34,6 +34,7 @@
 import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
 import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
 import static android.os.BatteryManager.CHARGING_POLICY_DEFAULT;
+import static android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING;
 
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
@@ -437,7 +438,8 @@
         }
     };
 
-    private final OnSubscriptionsChangedListener mSubscriptionListener =
+    @VisibleForTesting
+    final OnSubscriptionsChangedListener mSubscriptionListener =
             new OnSubscriptionsChangedListener() {
                 @Override
                 public void onSubscriptionsChanged() {
@@ -586,16 +588,14 @@
     private void handleSimSubscriptionInfoChanged() {
         Assert.isMainThread();
         mLogger.v("onSubscriptionInfoChanged()");
-        List<SubscriptionInfo> sil = mSubscriptionManager
-                .getCompleteActiveSubscriptionInfoList();
-        if (sil != null) {
-            for (SubscriptionInfo subInfo : sil) {
+        List<SubscriptionInfo> subscriptionInfos = getSubscriptionInfo(true /* forceReload */);
+        if (!subscriptionInfos.isEmpty()) {
+            for (SubscriptionInfo subInfo : subscriptionInfos) {
                 mLogger.logSubInfo(subInfo);
             }
         } else {
             mLogger.v("onSubscriptionInfoChanged: list is null");
         }
-        List<SubscriptionInfo> subscriptionInfos = getSubscriptionInfo(true /* forceReload */);
 
         // Hack level over 9000: Because the subscription id is not yet valid when we see the
         // first update in handleSimStateChange, we need to force refresh all SIM states
@@ -658,18 +658,18 @@
 
     /**
      * @return List of SubscriptionInfo records, maybe empty but never null.
+     *
+     * Note that this method will filter out any subscription which is PROFILE_CLASS_PROVISIONING
      */
     public List<SubscriptionInfo> getSubscriptionInfo(boolean forceReload) {
         List<SubscriptionInfo> sil = mSubscriptionInfo;
         if (sil == null || forceReload) {
-            sil = mSubscriptionManager.getCompleteActiveSubscriptionInfoList();
+            mSubscriptionInfo = mSubscriptionManager.getCompleteActiveSubscriptionInfoList()
+                    .stream()
+                    .filter(subInfo -> subInfo.getProfileClass() != PROFILE_CLASS_PROVISIONING)
+                    .toList();
         }
-        if (sil == null) {
-            // getCompleteActiveSubscriptionInfoList was null callers expect an empty list.
-            mSubscriptionInfo = new ArrayList<>();
-        } else {
-            mSubscriptionInfo = sil;
-        }
+
         return new ArrayList<>(mSubscriptionInfo);
     }
 
@@ -3313,6 +3313,7 @@
 
         becameAbsent |= ABSENT_SIM_STATE_LIST.contains(state);
 
+        // TODO(b/327476182): Preserve SIM_STATE_CARD_IO_ERROR sims in a separate data source.
         SimData data = mSimDatas.get(subId);
         final boolean changed;
         if (data == null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/CarrierTextManagerLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/CarrierTextManagerLogger.kt
index d02b72f..cb474d3 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/CarrierTextManagerLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/CarrierTextManagerLogger.kt
@@ -94,6 +94,20 @@
         )
     }
 
+    fun logSimStateChangedCallback(subId: Int, slotId: Int, simState: Int) {
+        buffer.log(
+            TAG,
+            LogLevel.VERBOSE,
+            {
+                // subId is always a very small int, and we've run out of integers for log buffer
+                long1 = subId.toLong()
+                int1 = slotId
+                int2 = simState
+            },
+            { "onSimStateChangedCallback: subId=$long1 slotId=$int1 simState=$int2" }
+        )
+    }
+
     /**
      * Used to log the starting point for _why_ the carrier text is updating. In order to keep us
      * from holding on to too many objects, we'll just use simple ints for reasons here
@@ -113,7 +127,7 @@
     companion object {
         const val REASON_REFRESH_CARRIER_INFO = 1
         const val REASON_ON_TELEPHONY_CAPABLE = 2
-        const val REASON_ON_SIM_STATE_CHANGED = 3
+        const val REASON_SIM_ERROR_STATE_CHANGED = 3
         const val REASON_ACTIVE_DATA_SUB_CHANGED = 4
 
         @Retention(AnnotationRetention.SOURCE)
@@ -122,7 +136,7 @@
                 [
                     REASON_REFRESH_CARRIER_INFO,
                     REASON_ON_TELEPHONY_CAPABLE,
-                    REASON_ON_SIM_STATE_CHANGED,
+                    REASON_SIM_ERROR_STATE_CHANGED,
                     REASON_ACTIVE_DATA_SUB_CHANGED,
                 ]
         )
@@ -132,7 +146,7 @@
             when (this) {
                 REASON_REFRESH_CARRIER_INFO -> "REFRESH_CARRIER_INFO"
                 REASON_ON_TELEPHONY_CAPABLE -> "ON_TELEPHONY_CAPABLE"
-                REASON_ON_SIM_STATE_CHANGED -> "SIM_STATE_CHANGED"
+                REASON_SIM_ERROR_STATE_CHANGED -> "SIM_ERROR_STATE_CHANGED"
                 REASON_ACTIVE_DATA_SUB_CHANGED -> "ACTIVE_DATA_SUB_CHANGED"
                 else -> "unknown"
             }
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
index d2ad096..ce4032a 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
@@ -16,6 +16,7 @@
 
 package com.android.keyguard.logging
 
+import android.hardware.biometrics.BiometricSourceType
 import com.android.systemui.biometrics.AuthRippleController
 import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController
 import com.android.systemui.log.LogBuffer
@@ -117,6 +118,26 @@
         )
     }
 
+    fun logDropNonFingerprintMessage(
+        message: CharSequence,
+        followUpMessage: CharSequence?,
+        biometricSourceType: BiometricSourceType?,
+    ) {
+        buffer.log(
+            KeyguardIndicationController.TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = message.toString()
+                str2 = followUpMessage?.toString()
+                str3 = biometricSourceType?.name
+            },
+            {
+                "droppingNonFingerprintMessage message=$str1 " +
+                    "followUpMessage:$str2 biometricSourceType:$str3"
+            }
+        )
+    }
+
     fun logUpdateBatteryIndication(
         powerIndication: String,
         pluggedIn: Boolean,
diff --git a/packages/SystemUI/src/com/android/systemui/DualToneHandler.kt b/packages/SystemUI/src/com/android/systemui/DualToneHandler.kt
index 22d0bc9..af810ea 100644
--- a/packages/SystemUI/src/com/android/systemui/DualToneHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/DualToneHandler.kt
@@ -20,6 +20,7 @@
 import android.content.Context
 import android.view.ContextThemeWrapper
 import com.android.settingslib.Utils
+import com.android.settingslib.flags.Flags.newStatusBarIcons
 import com.android.systemui.res.R
 
 /**
@@ -53,14 +54,26 @@
                 Utils.getThemeAttr(context, R.attr.darkIconTheme))
         val dualToneLightTheme = ContextThemeWrapper(context,
                 Utils.getThemeAttr(context, R.attr.lightIconTheme))
-        darkColor = Color(
-                Utils.getColorAttrDefaultColor(dualToneDarkTheme, R.attr.singleToneColor),
+        if (newStatusBarIcons()) {
+            darkColor = Color(
+                android.graphics.Color.BLACK,
                 Utils.getColorAttrDefaultColor(dualToneDarkTheme, R.attr.iconBackgroundColor),
                 Utils.getColorAttrDefaultColor(dualToneDarkTheme, R.attr.fillColor))
-        lightColor = Color(
-                Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.singleToneColor),
+
+            lightColor = Color(
+                android.graphics.Color.WHITE,
                 Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.iconBackgroundColor),
                 Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.fillColor))
+        } else {
+            darkColor = Color(
+                    Utils.getColorAttrDefaultColor(dualToneDarkTheme, R.attr.singleToneColor),
+                    Utils.getColorAttrDefaultColor(dualToneDarkTheme, R.attr.iconBackgroundColor),
+                    Utils.getColorAttrDefaultColor(dualToneDarkTheme, R.attr.fillColor))
+            lightColor = Color(
+                    Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.singleToneColor),
+                    Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.iconBackgroundColor),
+                    Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.fillColor))
+        }
     }
 
     private fun getColorForDarkIntensity(darkIntensity: Float, lightColor: Int, darkColor: Int) =
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java
index d2fda4c..88fa2de 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java
@@ -273,6 +273,10 @@
         }
     }
 
+    void onFullscreenMagnificationActivationChanged(int displayId, boolean activated) {
+        // Do nothing
+    }
+
     @MainThread
     void toggleSettingsPanelVisibility(int displayId) {
         final MagnificationSettingsController magnificationSettingsController =
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationConnectionImpl.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationConnectionImpl.java
index ba943b0..b5f3aef 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationConnectionImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationConnectionImpl.java
@@ -47,6 +47,12 @@
     }
 
     @Override
+    public void onFullscreenMagnificationActivationChanged(int displayId, boolean activated) {
+        mHandler.post(() -> mMagnification
+                .onFullscreenMagnificationActivationChanged(displayId, activated));
+    }
+
+    @Override
     public void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
             float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY,
             IRemoteMagnificationAnimationCallback callback) {
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 74ea58c..d30f33f 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -31,6 +31,7 @@
 import com.android.internal.app.IVoiceInteractionSessionListener;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.assist.domain.interactor.AssistInteractor;
 import com.android.systemui.assist.ui.DefaultUiController;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -149,6 +150,7 @@
     private final SecureSettings mSecureSettings;
     private final SelectedUserInteractor mSelectedUserInteractor;
     private final ActivityManager mActivityManager;
+    private final AssistInteractor mInteractor;
 
     private final DeviceProvisionedController mDeviceProvisionedController;
 
@@ -192,7 +194,8 @@
             DisplayTracker displayTracker,
             SecureSettings secureSettings,
             SelectedUserInteractor selectedUserInteractor,
-            ActivityManager activityManager) {
+            ActivityManager activityManager,
+            AssistInteractor interactor) {
         mContext = context;
         mDeviceProvisionedController = controller;
         mCommandQueue = commandQueue;
@@ -206,6 +209,7 @@
         mSecureSettings = secureSettings;
         mSelectedUserInteractor = selectedUserInteractor;
         mActivityManager = activityManager;
+        mInteractor = interactor;
 
         registerVoiceInteractionSessionListener();
         registerVisualQueryRecognitionStatusListener();
@@ -314,6 +318,7 @@
                 assistComponent,
                 legacyDeviceState);
         logStartAssistLegacy(legacyInvocationType, legacyDeviceState);
+        mInteractor.onAssistantStarted(legacyInvocationType);
         startAssistInternal(args, assistComponent, isService);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/assist/data/repository/AssistRepository.kt b/packages/SystemUI/src/com/android/systemui/assist/data/repository/AssistRepository.kt
new file mode 100644
index 0000000..c416c24
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/assist/data/repository/AssistRepository.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.assist.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.asSharedFlow
+
+@SysUISingleton
+class AssistRepository @Inject constructor() {
+    private val _latestInvocationType =
+        MutableSharedFlow<Int>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
+    /** The type of the latest invocation of the assistant. */
+    val latestInvocationType: SharedFlow<Int> = _latestInvocationType.asSharedFlow()
+
+    /** Sets the type of the latest invocation of the assistant. */
+    fun setLatestInvocationType(type: Int) {
+        _latestInvocationType.tryEmit(type)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/domain/interactor/AssistInteractor.kt b/packages/SystemUI/src/com/android/systemui/assist/domain/interactor/AssistInteractor.kt
new file mode 100644
index 0000000..d9e46aa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/assist/domain/interactor/AssistInteractor.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.assist.domain.interactor
+
+import com.android.systemui.Flags
+import com.android.systemui.assist.data.repository.AssistRepository
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.flow.SharedFlow
+
+@SysUISingleton
+class AssistInteractor
+@Inject
+constructor(
+    private val repository: AssistRepository,
+) {
+    /** The type of the latest invocation of the assistant. */
+    val latestInvocationType: SharedFlow<Int> = repository.latestInvocationType
+
+    /** Notifies that Assistant has been started. */
+    fun onAssistantStarted(type: Int) {
+        if (Flags.enableContextualTips() && Flags.enableContextualTipForPowerOff()) {
+            repository.setLatestInvocationType(type)
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index b1a153a..31698a3 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -17,6 +17,7 @@
 
 import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
 
+import static com.android.settingslib.flags.Flags.newStatusBarIcons;
 import static com.android.systemui.DejankUtils.whitelistIpcs;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -25,6 +26,7 @@
 import android.animation.ObjectAnimator;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -47,6 +49,9 @@
 
 import com.android.app.animation.Interpolators;
 import com.android.systemui.DualToneHandler;
+import com.android.systemui.battery.unified.BatteryColors;
+import com.android.systemui.battery.unified.BatteryDrawableState;
+import com.android.systemui.battery.unified.BatteryLayersDrawable;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.res.R;
@@ -78,6 +83,7 @@
     private boolean mShowPercentAvailable;
     private String mEstimateText = null;
     private boolean mPluggedIn;
+    private boolean mPowerSaveEnabled;
     private boolean mIsBatteryDefender;
     private boolean mIsIncompatibleCharging;
     private boolean mDisplayShieldEnabled;
@@ -91,6 +97,12 @@
 
     private BatteryEstimateFetcher mBatteryEstimateFetcher;
 
+    // for Flags.newStatusBarIcons. The unified battery icon can show percent inside
+    @Nullable private BatteryLayersDrawable mUnifiedBattery;
+    private BatteryColors mUnifiedBatteryColors = BatteryColors.LIGHT_THEME_COLORS;
+    private BatteryDrawableState mUnifiedBatteryState =
+            BatteryDrawableState.Companion.getDefaultInitialState();
+
     public BatteryMeterView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -106,6 +118,7 @@
         final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
                 context.getColor(com.android.settingslib.R.color.meter_background_color));
         mPercentageStyleId = atts.getResourceId(R.styleable.BatteryMeterView_textAppearance, 0);
+
         mDrawable = new AccessorizedBatteryDrawable(context, frameColor);
         atts.recycle();
 
@@ -115,13 +128,26 @@
         setupLayoutTransition();
 
         mBatteryIconView = new ImageView(context);
-        mBatteryIconView.setImageDrawable(mDrawable);
-        final MarginLayoutParams mlp = new MarginLayoutParams(
-                getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_width),
-                getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_height));
-        mlp.setMargins(0, 0, 0,
-                getResources().getDimensionPixelOffset(R.dimen.battery_margin_bottom));
-        addView(mBatteryIconView, mlp);
+        if (newStatusBarIcons()) {
+            mUnifiedBattery = BatteryLayersDrawable.Companion
+                    .newBatteryDrawable(context, mUnifiedBatteryState);
+            mBatteryIconView.setImageDrawable(mUnifiedBattery);
+
+            final MarginLayoutParams mlp = new MarginLayoutParams(
+                    getResources().getDimensionPixelSize(
+                            R.dimen.status_bar_battery_unified_icon_width),
+                    getResources().getDimensionPixelSize(
+                            R.dimen.status_bar_battery_unified_icon_height));
+            addView(mBatteryIconView, mlp);
+        } else {
+            mBatteryIconView.setImageDrawable(mDrawable);
+            final MarginLayoutParams mlp = new MarginLayoutParams(
+                    getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_width),
+                    getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_height));
+            mlp.setMargins(0, 0, 0,
+                    getResources().getDimensionPixelOffset(R.dimen.battery_margin_bottom));
+            addView(mBatteryIconView, mlp);
+        }
 
         updateShowPercent();
         mDualToneHandler = new DualToneHandler(context);
@@ -132,6 +158,14 @@
         setClipToPadding(false);
     }
 
+
+    private void setBatteryDrawableState(BatteryDrawableState newState) {
+        if (!newStatusBarIcons()) return;
+
+        mUnifiedBatteryState = newState;
+        mUnifiedBattery.setBatteryState(mUnifiedBatteryState);
+    }
+
     private void setupLayoutTransition() {
         LayoutTransition transition = new LayoutTransition();
         transition.setDuration(200);
@@ -200,25 +234,94 @@
      * @param pluggedIn whether the device is plugged in or not
      */
     public void onBatteryLevelChanged(@IntRange(from = 0, to = 100) int level, boolean pluggedIn) {
+        boolean wasCharging = isCharging();
         mPluggedIn = pluggedIn;
         mLevel = level;
-        mDrawable.setCharging(isCharging());
+        boolean isCharging = isCharging();
+        mDrawable.setCharging(isCharging);
         mDrawable.setBatteryLevel(level);
         updatePercentText();
+
+        if (newStatusBarIcons()) {
+            Drawable attr = mUnifiedBatteryState.getAttribution();
+            if (isCharging != wasCharging) {
+                attr = getBatteryAttribution(isCharging);
+            }
+
+            BatteryDrawableState newState =
+                    new BatteryDrawableState(
+                            level,
+                            mUnifiedBatteryState.getShowPercent(),
+                            level <= 20,
+                            attr
+                    );
+
+            setBatteryDrawableState(newState);
+        }
+    }
+
+    // Potentially reloads any attribution. Should not be called if the state hasn't changed
+    private Drawable getBatteryAttribution(boolean isCharging) {
+        if (!newStatusBarIcons()) return null;
+
+        int resId = 0;
+        if (mPowerSaveEnabled) {
+            resId = R.drawable.battery_unified_attr_powersave;
+        } else if (mIsBatteryDefender && mDisplayShieldEnabled) {
+            resId = R.drawable.battery_unified_attr_defend;
+        } else if (isCharging) {
+            resId = R.drawable.battery_unified_attr_charging;
+        }
+
+        Drawable attr = null;
+        if (resId > 0) {
+            attr = mContext.getDrawable(resId);
+        }
+
+        return attr;
     }
 
     void onPowerSaveChanged(boolean isPowerSave) {
-        mDrawable.setPowerSaveEnabled(isPowerSave);
+        if (isPowerSave == mPowerSaveEnabled) {
+            return;
+        }
+        mPowerSaveEnabled = isPowerSave;
+        if (!newStatusBarIcons()) {
+            mDrawable.setPowerSaveEnabled(isPowerSave);
+        } else {
+            setBatteryDrawableState(
+                    new BatteryDrawableState(
+                            mUnifiedBatteryState.getLevel(),
+                            mUnifiedBatteryState.getShowPercent(),
+                            mUnifiedBatteryState.getShowErrorState(),
+                            getBatteryAttribution(isCharging())
+                    )
+            );
+        }
     }
 
     void onIsBatteryDefenderChanged(boolean isBatteryDefender) {
         boolean valueChanged = mIsBatteryDefender != isBatteryDefender;
         mIsBatteryDefender = isBatteryDefender;
-        if (valueChanged) {
-            updateContentDescription();
+
+        if (!valueChanged) {
+            return;
+        }
+
+        updateContentDescription();
+        if (!newStatusBarIcons()) {
             // The battery drawable is a different size depending on whether it's currently
             // overheated or not, so we need to re-scale the view when overheated changes.
             scaleBatteryMeterViews();
+        } else {
+            setBatteryDrawableState(
+                    new BatteryDrawableState(
+                            mUnifiedBatteryState.getLevel(),
+                            mUnifiedBatteryState.getShowPercent(),
+                            mUnifiedBatteryState.getShowErrorState(),
+                            getBatteryAttribution(isCharging())
+                    )
+            );
         }
     }
 
@@ -226,7 +329,18 @@
         boolean valueChanged = mIsIncompatibleCharging != isIncompatibleCharging;
         mIsIncompatibleCharging = isIncompatibleCharging;
         if (valueChanged) {
-            mDrawable.setCharging(isCharging());
+            if (newStatusBarIcons()) {
+                setBatteryDrawableState(
+                        new BatteryDrawableState(
+                                mUnifiedBatteryState.getLevel(),
+                                mUnifiedBatteryState.getShowPercent(),
+                                mUnifiedBatteryState.getShowErrorState(),
+                                getBatteryAttribution(isCharging())
+                        )
+                );
+            } else {
+                mDrawable.setCharging(isCharging());
+            }
             updateContentDescription();
         }
     }
@@ -260,6 +374,38 @@
     }
 
     void updatePercentText() {
+        if (!newStatusBarIcons()) {
+            updatePercentTextLegacy();
+            return;
+        }
+
+        // The unified battery can show the percent inside, so we only need to handle
+        // the estimated time remaining case
+        if (mShowPercentMode == MODE_ESTIMATE
+                && mBatteryEstimateFetcher != null
+                && !isCharging()
+        ) {
+            mBatteryEstimateFetcher.fetchBatteryTimeRemainingEstimate(
+                    (String estimate) -> {
+                        if (mBatteryPercentView == null) {
+                            mBatteryPercentView = loadPercentView();
+                        }
+                        if (estimate != null && mShowPercentMode == MODE_ESTIMATE) {
+                            mEstimateText = estimate;
+                            mBatteryPercentView.setText(estimate);
+                            updateContentDescription();
+                        } else {
+                            mEstimateText = null;
+                            mBatteryPercentView.setText(null);
+                            updateContentDescription();
+                        }
+                    });
+        } else {
+            updateContentDescription();
+        }
+    }
+
+    void updatePercentTextLegacy() {
         if (mBatteryStateUnknown) {
             return;
         }
@@ -334,6 +480,45 @@
     }
 
     void updateShowPercent() {
+        if (!newStatusBarIcons()) {
+            updateShowPercentLegacy();
+            return;
+        }
+
+        if (mUnifiedBattery == null) {
+            return;
+        }
+
+        // TODO(b/140051051)
+        final boolean systemSetting = 0 != whitelistIpcs(() -> Settings.System
+                .getIntForUser(getContext().getContentResolver(),
+                SHOW_BATTERY_PERCENT, getContext().getResources().getBoolean(
+                com.android.internal.R.bool.config_defaultBatteryPercentageSetting)
+                ? 1 : 0, UserHandle.USER_CURRENT));
+
+        boolean shouldShow =
+                (mShowPercentAvailable && systemSetting && mShowPercentMode != MODE_OFF)
+                        || mShowPercentMode == MODE_ON;
+        shouldShow = shouldShow && !mBatteryStateUnknown;
+
+        setBatteryDrawableState(
+                new BatteryDrawableState(
+                        mUnifiedBatteryState.getLevel(),
+                        shouldShow,
+                        mUnifiedBatteryState.getShowErrorState(),
+                        mUnifiedBatteryState.getAttribution()
+                )
+        );
+
+        // The legacy impl used the percent view for the estimate and the percent text. The modern
+        // version only uses it for estimate. It can be safely removed here
+        if (mShowPercentMode != MODE_ESTIMATE) {
+            removeView(mBatteryPercentView);
+            mBatteryPercentView = null;
+        }
+    }
+
+    private void updateShowPercentLegacy() {
         final boolean showing = mBatteryPercentView != null;
         // TODO(b/140051051)
         final boolean systemSetting = 0 != whitelistIpcs(() -> Settings.System
@@ -395,10 +580,39 @@
         updateShowPercent();
     }
 
+    void scaleBatteryMeterViews() {
+        if (!newStatusBarIcons()) {
+            scaleBatteryMeterViewsLegacy();
+            return;
+        }
+
+        // For simplicity's sake, copy the general pattern in the legacy method and use the new
+        // resources, excluding what we don't need
+        Resources res = getContext().getResources();
+        TypedValue typedValue = new TypedValue();
+
+        res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
+        float iconScaleFactor = typedValue.getFloat();
+
+        float mainBatteryHeight =
+                res.getDimensionPixelSize(
+                        R.dimen.status_bar_battery_unified_icon_height) * iconScaleFactor;
+        float mainBatteryWidth =
+                res.getDimensionPixelSize(
+                        R.dimen.status_bar_battery_unified_icon_width) * iconScaleFactor;
+
+        LinearLayout.LayoutParams scaledLayoutParams = new LinearLayout.LayoutParams(
+                Math.round(mainBatteryWidth),
+                Math.round(mainBatteryHeight));
+
+        mBatteryIconView.setLayoutParams(scaledLayoutParams);
+        mBatteryIconView.invalidateDrawable(mUnifiedBattery);
+    }
+
     /**
      * Looks up the scale factor for status bar icons and scales the battery view by that amount.
      */
-    void scaleBatteryMeterViews() {
+    void scaleBatteryMeterViewsLegacy() {
         Resources res = getContext().getResources();
         TypedValue typedValue = new TypedValue();
 
@@ -445,6 +659,32 @@
     @Override
     public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
         if (mIsStaticColor) return;
+
+        if (!newStatusBarIcons()) {
+            onDarkChangedLegacy(areas, darkIntensity, tint);
+            return;
+        }
+
+        if (mUnifiedBattery == null) {
+            return;
+        }
+
+        if (DarkIconDispatcher.isInAreas(areas, this)) {
+            if (darkIntensity < 0.5) {
+                mUnifiedBatteryColors = BatteryColors.DARK_THEME_COLORS;
+            } else {
+                mUnifiedBatteryColors = BatteryColors.LIGHT_THEME_COLORS;
+            }
+
+            mUnifiedBattery.setColors(mUnifiedBatteryColors);
+        } else  {
+            // Same behavior as the legacy code when not isInArea
+            mUnifiedBatteryColors = BatteryColors.DARK_THEME_COLORS;
+            mUnifiedBattery.setColors(mUnifiedBatteryColors);
+        }
+    }
+
+    private void onDarkChangedLegacy(ArrayList<Rect> areas, float darkIntensity, int tint) {
         float intensity = DarkIconDispatcher.isInAreas(areas, this) ? darkIntensity : 0;
         int nonAdaptedSingleToneColor = mDualToneHandler.getSingleColor(intensity);
         int nonAdaptedForegroundColor = mDualToneHandler.getFillColor(intensity);
@@ -478,7 +718,16 @@
         }
     }
 
-    private boolean isCharging() {
+    /** For newStatusBarIcons(), we use a BatteryColors object to declare the theme */
+    public void setUnifiedBatteryColors(BatteryColors colors) {
+        if (!newStatusBarIcons()) return;
+
+        mUnifiedBatteryColors = colors;
+        mUnifiedBattery.setColors(mUnifiedBatteryColors);
+    }
+
+    @VisibleForTesting
+    boolean isCharging() {
         return mPluggedIn && !mIsIncompatibleCharging;
     }
 
@@ -505,6 +754,16 @@
         return mBatteryPercentView.getText();
     }
 
+    @VisibleForTesting
+    TextView getBatteryPercentView() {
+        return mBatteryPercentView;
+    }
+
+    @VisibleForTesting
+    BatteryDrawableState getUnifiedBatteryState() {
+        return mUnifiedBatteryState;
+    }
+
     /** An interface that will fetch the estimated time remaining for the user's battery. */
     public interface BatteryEstimateFetcher {
         void fetchBatteryTimeRemainingEstimate(
diff --git a/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryAttributionDrawable.kt b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryAttributionDrawable.kt
new file mode 100644
index 0000000..1b8495a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryAttributionDrawable.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.battery.unified
+
+import android.graphics.Canvas
+import android.graphics.ColorFilter
+import android.graphics.PixelFormat
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.DrawableWrapper
+import android.view.Gravity
+import kotlin.math.min
+import kotlin.math.roundToInt
+
+/**
+ * A battery attribution is defined as a drawable that can display either alongside the percent text
+ * or solely in the center of the battery frame.
+ *
+ * Attributions are given an explicit canvas of 18x8, or 6x6 depending on the display mode (centered
+ * or right-aligned). The size is configured in [BatteryLayersDrawable] by changing this drawable
+ * wrapper's bounds, and optionally setting the [gravity]
+ */
+@Suppress("RtlHardcoded")
+class BatteryAttributionDrawable(dr: Drawable?) : DrawableWrapper(dr) {
+    /** One of [CENTER, LEFT]. Note that RTL is handled in the parent */
+    var gravity = Gravity.CENTER
+        set(value) {
+            field = value
+            updateBoundsInner()
+        }
+
+    // Must be called if bounds change, gravity changes, or the wrapped drawable changes
+    private fun updateBoundsInner() {
+        val dr = drawable ?: return
+
+        val hScale = bounds.width().toFloat() / dr.intrinsicWidth.toFloat()
+        val vScale = bounds.height().toFloat() / dr.intrinsicHeight.toFloat()
+        val scale = min(hScale, vScale)
+
+        val dw = scale * dr.intrinsicWidth
+        val dh = scale * dr.intrinsicHeight
+
+        if (gravity == Gravity.CENTER) {
+            val padLeft = (bounds.width() - dw) / 2
+            val padTop = (bounds.height() - dh) / 2
+            dr.setBounds(
+                (bounds.left + padLeft).roundToInt(),
+                (bounds.top + padTop).roundToInt(),
+                (bounds.left + padLeft + dw).roundToInt(),
+                (bounds.top + padTop + dh).roundToInt()
+            )
+        } else if (gravity == Gravity.LEFT) {
+            dr.setBounds(
+                bounds.left,
+                bounds.top,
+                (bounds.left + dw).roundToInt(),
+                (bounds.top + dh).roundToInt()
+            )
+        }
+    }
+
+    override fun setDrawable(dr: Drawable?) {
+        super.setDrawable(dr)
+        updateBoundsInner()
+    }
+
+    override fun onBoundsChange(bounds: Rect) {
+        updateBoundsInner()
+    }
+
+    /**
+     * DrawableWrapper allows for a null constructor, but this method assumes that the drawable is
+     * non-null. It is called by LayerDrawable on init, so we have to handle null here specifically
+     */
+    override fun getChangingConfigurations(): Int = drawable?.changingConfigurations ?: 0
+
+    override fun draw(canvas: Canvas) {
+        drawable?.draw(canvas)
+    }
+
+    // Deprecated, but needed for Drawable implementation
+    override fun getOpacity() = PixelFormat.OPAQUE
+
+    // We don't use this
+    override fun setAlpha(alpha: Int) {}
+
+    override fun setColorFilter(colorFilter: ColorFilter?) {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryDrawableState.kt b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryDrawableState.kt
new file mode 100644
index 0000000..b5a93b6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryDrawableState.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.battery.unified
+
+import android.graphics.Color
+import android.graphics.drawable.Drawable
+
+/**
+ * Encapsulates all drawing information needed by BatteryMeterDrawable to render properly. Rendered
+ * state will be equivalent to the most recent state passed in.
+ */
+data class BatteryDrawableState(
+    /** [0-100] description of the battery level */
+    val level: Int,
+    /** Whether or not to render the percent as a foreground text layer */
+    val showPercent: Boolean,
+    /**
+     * In an error state, the drawable will use the error colors and removes the third layer. If
+     * [showPercent] is false, then the fill will be rendered in the foreground error color. Else
+     * the fill is not rendered.
+     */
+    val showErrorState: Boolean,
+
+    /**
+     * An attribution is a drawable that shows either alongside the percent, or centered in the
+     * foreground of the overall drawable.
+     *
+     * When space sharing with the percent text, the default rect is 6x6, positioned directly next
+     * to the percent and left-aligned.
+     *
+     * When the attribution is the only foreground layer, then we use a 16x8 canvas and center this
+     * drawable.
+     *
+     * In both cases, we use a FIT_CENTER style scaling. Note that for now the attributions will
+     * have to configure their own padding inside of their vector definitions. Future versions
+     * should abstract the side- and center- canvases and allow attributions to be defined with
+     * separate designs for each case.
+     */
+    val attribution: Drawable?
+) {
+    fun hasForegroundContent() = showPercent || attribution != null
+
+    companion object {
+        val DefaultInitialState =
+            BatteryDrawableState(
+                level = 50,
+                showPercent = false,
+                showErrorState = false,
+                attribution = null,
+            )
+    }
+}
+
+sealed interface BatteryColors {
+    /** The color for the frame and any foreground attributions for the battery */
+    val fg: Int
+    /**
+     * Default color for the frame background. Configured to be a transparent white or black that
+     * matches the current mode (white for light theme, black for dark theme) and provides extra
+     * contrast for the drawable
+     */
+    val bg: Int
+
+    /** Color for the level fill when there is an attribution on top */
+    val fill: Int
+    /**
+     * When there is no attribution, [fillOnlyColor] describes an opaque color with more contrast
+     */
+    val fillOnly: Int
+
+    /** Error colors are used for low battery states typically */
+    val errorForeground: Int
+    val errorBackground: Int
+
+    /** Currently unused */
+    val warnBackground: Int
+
+    /** Color scheme appropriate for light mode (dark icons) */
+    data object LightThemeColors : BatteryColors {
+        override val fg = Color.BLACK
+        // 22% alpha white
+        override val bg: Int = Color.valueOf(1f, 1f, 1f, 0.22f).toArgb()
+
+        // 18% alpha black
+        override val fill = Color.valueOf(0f, 0f, 0f, 0.18f).toArgb()
+        // GM Gray 500
+        override val fillOnly = Color.parseColor("#9AA0A6")
+
+        // GM Red 600
+        override val errorForeground = Color.parseColor("#D93025")
+        // GM Red 100
+        override val errorBackground = Color.parseColor("#FAD2CF")
+
+        // GM Yellow 500
+        override val warnBackground = Color.parseColor("#FBBC04")
+    }
+
+    /** Color scheme appropriate for dark mode (light icons) */
+    data object DarkThemeColors : BatteryColors {
+        override val fg = Color.WHITE
+        // 18% alpha black
+        override val bg: Int = Color.valueOf(0f, 0f, 0f, 0.18f).toArgb()
+
+        // 22% alpha white
+        override val fill = Color.valueOf(1f, 1f, 1f, 0.22f).toArgb()
+        // GM Gray 600
+        override val fillOnly = Color.parseColor("#80868B")
+
+        // GM Red 600
+        override val errorForeground = Color.parseColor("#D93025")
+        // GM Red 200
+        override val errorBackground = Color.parseColor("#F6AEA9")
+        // GM Yellow
+        override val warnBackground = Color.parseColor("#FBBC04")
+    }
+
+    companion object {
+        /** For use from java */
+        @JvmField val LIGHT_THEME_COLORS = LightThemeColors
+
+        @JvmField val DARK_THEME_COLORS = DarkThemeColors
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryFillDrawable.kt b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryFillDrawable.kt
new file mode 100644
index 0000000..6d32067
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryFillDrawable.kt
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.battery.unified
+
+import android.graphics.BlendMode
+import android.graphics.Canvas
+import android.graphics.ColorFilter
+import android.graphics.Matrix
+import android.graphics.Paint
+import android.graphics.Path
+import android.graphics.PixelFormat
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.drawable.Drawable
+import com.android.systemui.battery.unified.BatteryLayersDrawable.Companion.Metrics
+import kotlin.math.floor
+import kotlin.math.roundToInt
+
+/**
+ * Draws a right-to-left fill inside of the given [framePath]. This fill is designed to exactly fill
+ * the usable space inside of [framePath], given that the stroke width of the path is 1.5, and we
+ * want an extra 0.25 (canvas units) of a gap between the fill and the stroke
+ */
+class BatteryFillDrawable(private val framePath: Path) : Drawable() {
+    private var hScale = 1f
+    private val scaleMatrix = Matrix().also { it.setScale(1f, 1f) }
+    private val scaledPath = Path()
+    private val scaledFillRect = RectF()
+    private var scaledLeftOffset = 0f
+    private var scaledRightInset = 0f
+
+    // Drawable.level cannot be overloaded
+    var batteryLevel = 0
+        set(value) {
+            field = value
+            invalidateSelf()
+        }
+
+    var fillColor: Int = 0
+        set(value) {
+            field = value
+            fillPaint.color = value
+            invalidateSelf()
+        }
+
+    private val clearPaint =
+        Paint(Paint.ANTI_ALIAS_FLAG).also { p ->
+            p.style = Paint.Style.STROKE
+            p.strokeWidth = 5f
+            p.blendMode = BlendMode.CLEAR
+        }
+
+    private val fillPaint =
+        Paint(Paint.ANTI_ALIAS_FLAG).also { p ->
+            p.style = Paint.Style.FILL
+            p.color = fillColor
+        }
+
+    override fun onBoundsChange(bounds: Rect) {
+        super.onBoundsChange(bounds)
+
+        hScale = bounds.right / Metrics.ViewportWidth
+
+        if (bounds.isEmpty) {
+            scaleMatrix.setScale(1f, 1f)
+        } else {
+            scaleMatrix.setScale(
+                (bounds.right / Metrics.ViewportWidth),
+                (bounds.bottom / Metrics.ViewportHeight)
+            )
+        }
+
+        updateScale()
+    }
+
+    private fun updateScale() {
+        framePath.transform(/* matrix = */ scaleMatrix, /* dst = */ scaledPath)
+        scaleMatrix.mapRect(/* dst = */ scaledFillRect, /* src = */ FillRect)
+
+        scaledLeftOffset = LeftFillOffset * hScale
+        scaledRightInset = RightFillInset * hScale
+    }
+
+    override fun draw(canvas: Canvas) {
+        if (batteryLevel == 0) {
+            return
+        }
+
+        // saveLayer is needed here so we don't clip the other layers of our drawable
+        canvas.saveLayer(null, null)
+
+        // We need to use 3 draw commands:
+        // 1. Clip to the current level
+        // 2. Clip anything outside of the path
+        // 3. render the fill as a rect the correct size to fit the inner space
+        // 4. Clip out the padding between the frame and the fill
+
+        val fillLeft: Int =
+            if (batteryLevel == 100) {
+                0
+            } else {
+                val fillFraction = batteryLevel / 100f
+                floor(scaledFillRect.width() * (1 - fillFraction)).roundToInt()
+            }
+
+        // Clip to the fill level
+        canvas.clipOutRect(
+            scaledLeftOffset,
+            bounds.top.toFloat(),
+            scaledLeftOffset + fillLeft,
+            bounds.height().toFloat()
+        )
+        // Clip everything outside of the path
+        canvas.clipPath(scaledPath)
+
+        // Draw the fill
+        canvas.drawRect(scaledFillRect, fillPaint)
+
+        // Clear around the fill
+        canvas.drawPath(scaledPath, clearPaint)
+
+        // Finally, restore the layer
+        canvas.restore()
+    }
+
+    override fun setColorFilter(colorFilter: ColorFilter?) {
+        clearPaint.setColorFilter(colorFilter)
+        fillPaint.setColorFilter(colorFilter)
+    }
+
+    // unused
+    override fun getOpacity(): Int = PixelFormat.OPAQUE
+
+    // unused
+    override fun setAlpha(alpha: Int) {}
+
+    companion object {
+        // 3.75f =
+        //       2.75 (left-most edge of the frame path)
+        //     + 0.75 (1/2 of the stroke width)
+        //     + 0.25 (padding between stroke and fill edge)
+        private const val LeftFillOffset = 3.75f
+
+        // 1.75, calculated the same way, but from the right edge (without the battery cap), which
+        // consumes 2 units of width.
+        private const val RightFillInset = 1.75f
+
+        /** Scale this to the viewport so we fill correctly! */
+        private val FillRect =
+            RectF(
+                LeftFillOffset,
+                0f,
+                Metrics.ViewportWidth - RightFillInset,
+                Metrics.ViewportHeight
+            )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryLayersDrawable.kt b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryLayersDrawable.kt
new file mode 100644
index 0000000..199dd1f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryLayersDrawable.kt
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.battery.unified
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Matrix
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.Typeface
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.LayerDrawable
+import android.util.PathParser
+import android.view.Gravity
+import com.android.systemui.res.R
+import kotlin.math.roundToInt
+
+/**
+ * Custom [Drawable] that manages a list of other drawables which, together, achieve an appropriate
+ * view for [BatteryDrawableState].
+ *
+ * The main elements managed by this drawable are:
+ *
+ *      1. A battery frame background, which may show a solid fill color
+ *      2. The battery frame itself
+ *      3. A custom [BatteryFillDrawable], which renders a fill level, appropriately scale and
+ *         clipped to the battery percent
+ *      4. Percent text
+ *      5. An attribution
+ *
+ * Layers (1) and (2) are loaded directly from xml, as they are static assets. Layer (3) contains a
+ * custom [Drawable.draw] implementation and uses the same path as the battery shape to achieve an
+ * appropriate fill shape.
+ *
+ * The text and attribution layers have the following behaviors:
+ *
+ *      - When text-only or attribute-only, the foreground layer is centered and the maximum size
+ *      - When sharing space between the attribute and the text:
+ *          - The internal space is divided into 12x10 and 6x6 rectangles
+ *          - The attribution is aligned left
+ *          - The percent text is scaled based on the number of characters (1,2, or 3) in the string
+ *
+ * When [BatteryDrawableState.showErrorState] is true, we will only show either the percent text OR
+ * the battery fill, in order to maximize contrast when using the error colors.
+ */
+@Suppress("RtlHardcoded")
+class BatteryLayersDrawable(
+    private val frameBg: Drawable,
+    private val frame: Drawable,
+    private val fill: BatteryFillDrawable,
+    private val textOnly: BatteryPercentTextOnlyDrawable,
+    private val spaceSharingText: BatterySpaceSharingPercentTextDrawable,
+    private val attribution: BatteryAttributionDrawable,
+    batteryState: BatteryDrawableState,
+) : LayerDrawable(arrayOf(frameBg, frame, fill, textOnly, spaceSharingText, attribution)) {
+
+    private val scaleMatrix = Matrix().also { it.setScale(1f, 1f) }
+    private val scaledAttrFullCanvas = RectF(Metrics.AttrFullCanvas)
+    private val scaledAttrRightCanvas = RectF(Metrics.AttrRightCanvas)
+
+    var batteryState = batteryState
+        set(value) {
+            if (field != value) {
+                // Update before we set the backing field so we can diff
+                handleUpdateState(field, value)
+                field = value
+                invalidateSelf()
+            }
+        }
+
+    var colors: BatteryColors = BatteryColors.LightThemeColors
+        set(value) {
+            field = value
+            updateColors(batteryState.showErrorState, value)
+        }
+
+    private fun handleUpdateState(old: BatteryDrawableState, new: BatteryDrawableState) {
+        if (new.showErrorState != old.showErrorState) {
+            updateColors(new.showErrorState, colors)
+        }
+
+        if (new.level != old.level) {
+            fill.batteryLevel = new.level
+            textOnly.batteryLevel = new.level
+            spaceSharingText.batteryLevel = new.level
+        }
+
+        if (new.attribution != null && new.attribution != attribution.drawable) {
+            attribution.drawable = new.attribution
+            updateColors(new.showErrorState, colors)
+        }
+
+        if (new.hasForegroundContent() != old.hasForegroundContent()) {
+            setFillColor(new.hasForegroundContent(), new.showErrorState, colors)
+        }
+    }
+
+    /** In error states, we don't draw fill unless there is no foreground content (e.g., percent) */
+    private fun updateColors(showErrorState: Boolean, colorInfo: BatteryColors) {
+        frameBg.setTint(if (showErrorState) colorInfo.errorBackground else colorInfo.bg)
+        frame.setTint(colorInfo.fg)
+        attribution.setTint(if (showErrorState) colorInfo.errorForeground else colorInfo.fg)
+        textOnly.setTint(if (showErrorState) colorInfo.errorForeground else colorInfo.fg)
+        spaceSharingText.setTint(if (showErrorState) colorInfo.errorForeground else colorInfo.fg)
+        setFillColor(batteryState.hasForegroundContent(), showErrorState, colorInfo)
+    }
+
+    /**
+     * If there is a foreground layer, then we draw the fill with the low opacity
+     * [BatteryColors.fill] color. Otherwise, if there is no other foreground layer, we will use
+     * either the error or fillOnly colors for more contrast
+     */
+    private fun setFillColor(
+        hasFg: Boolean,
+        error: Boolean,
+        colorInfo: BatteryColors,
+    ) {
+        if (hasFg) {
+            fill.fillColor = colorInfo.fill
+        } else {
+            fill.fillColor = if (error) colorInfo.errorForeground else colorInfo.fillOnly
+        }
+    }
+
+    override fun onBoundsChange(bounds: Rect) {
+        super.onBoundsChange(bounds)
+
+        scaleMatrix.setScale(
+            bounds.width() / Metrics.ViewportWidth,
+            bounds.height() / Metrics.ViewportHeight
+        )
+
+        // Scale the attribution bounds
+        scaleMatrix.mapRect(scaledAttrFullCanvas, Metrics.AttrFullCanvas)
+        scaleMatrix.mapRect(scaledAttrRightCanvas, Metrics.AttrRightCanvas)
+    }
+
+    override fun draw(canvas: Canvas) {
+        // 1. Draw the frame bg
+        frameBg.draw(canvas)
+        // 2. Then the frame itself
+        frame.draw(canvas)
+
+        // 3. Fill it the appropriate amount if non-error state or error + no attribute
+        if (!batteryState.showErrorState || !batteryState.hasForegroundContent()) {
+            fill.draw(canvas)
+        }
+        // 4. Decide what goes inside
+        if (batteryState.showPercent && batteryState.attribution != null) {
+            // 4a. percent & attribution. Implies space-sharing
+
+            // Configure the attribute to draw in a smaller bounding box and align left
+            attribution.gravity = Gravity.LEFT
+            attribution.setBounds(
+                scaledAttrRightCanvas.left.roundToInt(),
+                scaledAttrRightCanvas.top.roundToInt(),
+                scaledAttrRightCanvas.right.roundToInt(),
+                scaledAttrRightCanvas.bottom.roundToInt(),
+            )
+            attribution.draw(canvas)
+
+            spaceSharingText.draw(canvas)
+        } else if (batteryState.showPercent) {
+            // 4b. Percent only
+            textOnly.draw(canvas)
+        } else if (batteryState.attribution != null) {
+            // 4c. Attribution only
+            attribution.gravity = Gravity.CENTER
+            attribution.setBounds(
+                scaledAttrFullCanvas.left.roundToInt(),
+                scaledAttrFullCanvas.top.roundToInt(),
+                scaledAttrFullCanvas.right.roundToInt(),
+                scaledAttrFullCanvas.bottom.roundToInt(),
+            )
+            attribution.draw(canvas)
+        }
+    }
+
+    /**
+     * This drawable relies on [BatteryColors] to encode all alpha in their values, so we ignore
+     * externally-set alpha
+     */
+    override fun setAlpha(alpha: Int) {}
+
+    interface M {
+        val ViewportWidth: Float
+        val ViewportHeight: Float
+
+        // Bounds, oriented in the above viewport, where we will fit-center and center-align
+        // an attribution that is the sole foreground element
+        val AttrFullCanvas: RectF
+        // Bounds, oriented in the above viewport, where we will fit-center and left-align
+        // an attribution that is sharing space with the percent text of the drawable
+        val AttrRightCanvas: RectF
+    }
+
+    companion object {
+        private val PercentFont = Typeface.create("google-sans", Typeface.BOLD)
+
+        /**
+         * Think of this like the `android:<attr>` values in a drawable.xml file. [Metrics] defines
+         * relevant canvas and size information for us to layout this cluster of drawables
+         */
+        val Metrics =
+            object : M {
+                override val ViewportWidth: Float = 24f
+                override val ViewportHeight: Float = 14f
+
+                /**
+                 * Bounds, oriented in the above viewport, where we will fit-center and center-align
+                 * an attribution that is the sole foreground element
+                 *
+                 * 18x8 point size
+                 */
+                override val AttrFullCanvas: RectF = RectF(4f, 3f, 22f, 11f)
+                /**
+                 * Bounds, oriented in the above viewport, where we will fit-center and left-align
+                 * an attribution that is sharing space with the percent text of the drawable
+                 *
+                 * 6x6 point size
+                 */
+                override val AttrRightCanvas: RectF = RectF(16f, 4f, 22f, 10f)
+            }
+
+        /**
+         * Create all of the layers needed by [BatteryLayersDrawable]. This class relies on the
+         * following resources to exist in order to properly render:
+         * - R.drawable.battery_unified_frame_bg
+         * - R.drawable.battery_unified_frame
+         * - R.string.battery_unified_frame_path_string
+         * - GoogleSans bold font
+         *
+         * See [BatteryDrawableState] for how to set the properties of the resulting class
+         */
+        fun newBatteryDrawable(
+            context: Context,
+            initialState: BatteryDrawableState = BatteryDrawableState.DefaultInitialState,
+        ): BatteryLayersDrawable {
+            val framePath =
+                PathParser.createPathFromPathData(
+                    context.getString(R.string.battery_unified_frame_path_string)
+                )
+
+            val frameBg =
+                context.getDrawable(R.drawable.battery_unified_frame_bg)
+                    ?: throw IllegalStateException("Missing battery_unified_frame_bg.xml")
+            val frame =
+                context.getDrawable(R.drawable.battery_unified_frame)
+                    ?: throw IllegalStateException("Missing battery_unified_frame.xml")
+            val fill = BatteryFillDrawable(framePath)
+            val textOnly = BatteryPercentTextOnlyDrawable(PercentFont)
+            val spaceSharingText = BatterySpaceSharingPercentTextDrawable(PercentFont)
+            val attribution = BatteryAttributionDrawable(null)
+
+            return BatteryLayersDrawable(
+                frameBg = frameBg,
+                frame = frame,
+                fill = fill,
+                textOnly = textOnly,
+                spaceSharingText = spaceSharingText,
+                attribution = attribution,
+                batteryState = initialState,
+            )
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryPercentTextOnlyDrawable.kt b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryPercentTextOnlyDrawable.kt
new file mode 100644
index 0000000..123d6ba
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryPercentTextOnlyDrawable.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.battery.unified
+
+import android.graphics.Canvas
+import android.graphics.ColorFilter
+import android.graphics.Paint
+import android.graphics.PixelFormat
+import android.graphics.Rect
+import android.graphics.Typeface
+import android.graphics.drawable.Drawable
+import com.android.systemui.battery.unified.BatteryLayersDrawable.Companion.Metrics
+
+/**
+ * (Names are hard) this drawable calculates the percent text for inside of the
+ * [BatteryLayersDrawable], assuming that there is no other attribution in the foreground. In this
+ * case, we can use the maximum font size and center the text in the full render area inside of the
+ * frame. After accounting for the stroke width and the insets from there, our rendering area is
+ * 18x10 points.
+ *
+ * See [BatterySpaceSharingPercentTextDrawable] (names are still hard) for the space-sharing
+ * approach.
+ *
+ * Note that these drawing metrics are only tested to work with google-sans BOLD
+ */
+class BatteryPercentTextOnlyDrawable(font: Typeface) : Drawable() {
+    private var hScale = 1f
+    private var vScale = 1f
+
+    // range 0-100
+    var batteryLevel: Int = 100
+        set(value) {
+            field = value
+            percentText = "$value"
+            invalidateSelf()
+        }
+
+    private var percentText = "$batteryLevel"
+
+    private val textPaint =
+        Paint().also { p ->
+            p.textSize = 10f
+            p.typeface = font
+        }
+
+    override fun onBoundsChange(bounds: Rect) {
+        super.onBoundsChange(bounds)
+
+        vScale = bounds.bottom / Metrics.ViewportHeight
+        hScale = bounds.right / Metrics.ViewportWidth
+
+        updateScale()
+    }
+
+    private fun updateScale() {
+        textPaint.textSize = TextSize * vScale
+    }
+
+    override fun draw(canvas: Canvas) {
+        val totalAvailableHeight = CanvasHeight * vScale
+
+        // Distribute the vertical whitespace around the text. This is a simplified version of
+        // the equation ((C - T) / 2) + T - V, where C == canvas height, T == text height, and V
+        // is the vertical nudge.
+        val offsetY = (totalAvailableHeight + textPaint.textSize) / 2 - (VerticalNudge * vScale)
+
+        val totalAvailableWidth = CanvasWidth * hScale
+        val textWidth = textPaint.measureText(percentText)
+        val offsetX = (totalAvailableWidth - textWidth) / 2
+
+        // Draw the text centered in the available area
+        canvas.drawText(
+            percentText,
+            (ViewportInsetLeft * hScale) + offsetX,
+            (ViewportInsetTop * vScale) + offsetY,
+            textPaint
+        )
+    }
+
+    override fun setTint(tintColor: Int) {
+        textPaint.color = tintColor
+        super.setTint(tintColor)
+    }
+
+    override fun getOpacity() = PixelFormat.OPAQUE
+
+    override fun setAlpha(alpha: Int) {}
+
+    override fun setColorFilter(colorFilter: ColorFilter?) {}
+
+    companion object {
+        // Based on the 24x14 canvas, we can render in an 18x10 canvas, inset like so:
+        const val ViewportInsetLeft = 4f
+        const val ViewportInsetRight = 2f
+        const val ViewportInsetTop = 2f
+        const val CanvasHeight = 10f
+        const val CanvasWidth = 18f
+
+        // raise the text up by a smidgen so that it is more centered. Experimentally determined
+        const val VerticalNudge = 1.5f
+
+        // Experimentally-determined value
+        const val TextSize = 10f
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/battery/unified/BatterySpaceSharingPercentTextDrawable.kt b/packages/SystemUI/src/com/android/systemui/battery/unified/BatterySpaceSharingPercentTextDrawable.kt
new file mode 100644
index 0000000..0c418b9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/battery/unified/BatterySpaceSharingPercentTextDrawable.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.battery.unified
+
+import android.graphics.Canvas
+import android.graphics.ColorFilter
+import android.graphics.Paint
+import android.graphics.PixelFormat
+import android.graphics.Rect
+import android.graphics.Typeface
+import android.graphics.drawable.Drawable
+import com.android.systemui.battery.unified.BatteryLayersDrawable.Companion.Metrics
+
+/**
+ * A variant of [BatteryPercentTextOnlyDrawable] with the following differences:
+ * 1. It is defined on a canvas of 12x10 (shortened by 6 points horizontally)
+ * 2. Because of this, we scale the font according to the number of characters
+ *
+ * Note that these drawing metrics are only tested to work with google-sans BOLD
+ */
+class BatterySpaceSharingPercentTextDrawable(font: Typeface) : Drawable() {
+    private var verticalNudge = 0f
+    private var hScale = 1f
+    private var vScale = 1f
+
+    // range 0-100
+    var batteryLevel: Int = 88
+        set(value) {
+            field = value
+            percentText = "$value"
+            invalidateSelf()
+        }
+
+    private var percentText = "$batteryLevel"
+        set(value) {
+            field = value
+            numberOfCharacters = percentText.length
+        }
+
+    private var numberOfCharacters = percentText.length
+        set(value) {
+            if (field != value) {
+                field = value
+                updateFontSize()
+            }
+        }
+
+    private val textPaint =
+        Paint().also { p ->
+            p.textSize = 10f
+            p.typeface = font
+        }
+
+    private fun updateFontSize() {
+        // These values are determined experimentally
+        when (numberOfCharacters) {
+            3 -> {
+                verticalNudge = 1f
+                textPaint.textSize = 6f * hScale
+            }
+            // 1, 2
+            else -> {
+                verticalNudge = 1.25f
+                textPaint.textSize = 9f * hScale
+            }
+        }
+    }
+
+    private fun updateScale() {
+        updateFontSize()
+    }
+
+    override fun onBoundsChange(bounds: Rect) {
+        super.onBoundsChange(bounds)
+
+        hScale = bounds.right / Metrics.ViewportWidth
+        vScale = bounds.bottom / Metrics.ViewportHeight
+
+        updateScale()
+    }
+
+    override fun draw(canvas: Canvas) {
+        val totalAvailableHeight = CanvasHeight * vScale
+
+        // Distribute the vertical whitespace around the text. This is a simplified version of
+        // the equation ((C - T) / 2) + T - V, where C == canvas height, T == text height, and V
+        // is the vertical nudge.
+        val offsetY = (totalAvailableHeight + textPaint.textSize) / 2 - (verticalNudge * vScale)
+
+        val totalAvailableWidth = CanvasWidth * hScale
+        val textWidth = textPaint.measureText(percentText)
+        val offsetX = (totalAvailableWidth - textWidth) / 2
+
+        canvas.drawText(
+            percentText,
+            (ViewportInsetLeft * hScale) + offsetX,
+            (ViewportInsetTop * vScale) + offsetY,
+            textPaint
+        )
+    }
+
+    override fun setTint(tintColor: Int) {
+        textPaint.color = tintColor
+        super.setTint(tintColor)
+    }
+
+    override fun getOpacity() = PixelFormat.OPAQUE
+
+    override fun setAlpha(p0: Int) {}
+
+    override fun setColorFilter(colorFilter: ColorFilter?) {
+        textPaint.colorFilter = colorFilter
+    }
+
+    companion object {
+        private const val ViewportInsetLeft = 4f
+        private const val ViewportInsetTop = 2f
+
+        private const val CanvasWidth = 12f
+        private const val CanvasHeight = 10f
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 0bd44f0..9de71c1 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -17,7 +17,7 @@
 package com.android.systemui.biometrics;
 
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
-import static android.hardware.biometrics.Flags.customBiometricPrompt;
+import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_BIOMETRIC_PROMPT_TRANSITION;
@@ -33,6 +33,7 @@
 import android.hardware.biometrics.BiometricAuthenticator.Modality;
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.BiometricManager.Authenticators;
+import android.hardware.biometrics.Flags;
 import android.hardware.biometrics.PromptInfo;
 import android.hardware.face.FaceSensorPropertiesInternal;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -43,6 +44,7 @@
 import android.os.UserManager;
 import android.util.Log;
 import android.view.Display;
+import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -160,6 +162,8 @@
     private final ImageView mBackgroundView;
     private final ScrollView mBiometricScrollView;
     private final View mPanelView;
+    private final List<FingerprintSensorPropertiesInternal> mFpProps;
+    private final List<FaceSensorPropertiesInternal> mFaceProps;
     private final float mTranslationY;
     @VisibleForTesting @ContainerState int mContainerState = STATE_UNKNOWN;
     private final Set<Integer> mFailedModalities = new HashSet<Integer>();
@@ -374,6 +378,8 @@
         mPromptSelectorInteractorProvider = promptSelectorInteractorProvider;
         mCredentialViewModelProvider = credentialViewModelProvider;
         mPromptViewModel = promptViewModel;
+        mFpProps = fpProps;
+        mFaceProps = faceProps;
 
         showPrompt(config, layoutInflater, promptViewModel,
                 Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds),
@@ -402,7 +408,12 @@
             @Nullable FaceSensorPropertiesInternal faceProps,
             @NonNull VibratorHelper vibratorHelper
     ) {
-        if (Utils.isBiometricAllowed(config.mPromptInfo) || customBiometricPrompt()) {
+        // Set this value before showing either of the prompt.
+        mPromptSelectorInteractorProvider.get().setShouldShowBpWithoutIconForCredential(
+                config.mPromptInfo);
+
+        if (Utils.isBiometricAllowed(config.mPromptInfo)
+                || mPromptViewModel.getShowBpWithoutIconForCredential().getValue()) {
             addBiometricView(config, layoutInflater, viewModel, fpProps, faceProps, vibratorHelper);
         } else if (constraintBp() && Utils.isDeviceCredentialAllowed(mConfig.mPromptInfo)) {
             addCredentialView(true, false);
@@ -411,7 +422,6 @@
         }
     }
 
-
     private void addBiometricView(@NonNull Config config, @NonNull LayoutInflater layoutInflater,
             @NonNull PromptViewModel viewModel,
             @Nullable FingerprintSensorPropertiesInternal fpProps,
@@ -517,7 +527,7 @@
     @Override
     public void onOrientationChanged() {
         if (!constraintBp()) {
-            maybeUpdatePositionForUdfps(true /* invalidate */);
+            updatePositionByCapability(true /* invalidate */);
         }
     }
 
@@ -534,7 +544,8 @@
                 () -> animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED));
         if (constraintBp()) {
             // Do nothing on attachment with constraintLayout
-        } else if (Utils.isBiometricAllowed(mConfig.mPromptInfo) || customBiometricPrompt()) {
+        } else if (Utils.isBiometricAllowed(mConfig.mPromptInfo)
+                || mPromptViewModel.getShowBpWithoutIconForCredential().getValue()) {
             mBiometricScrollView.addView(mBiometricView.asView());
         } else if (Utils.isDeviceCredentialAllowed(mConfig.mPromptInfo)) {
             addCredentialView(true /* animatePanel */, false /* animateContents */);
@@ -544,7 +555,7 @@
         }
 
         if (!constraintBp()) {
-            maybeUpdatePositionForUdfps(false /* invalidate */);
+            updatePositionByCapability(false /* invalidate */);
         }
 
         if (mConfig.mSkipIntro) {
@@ -610,6 +621,22 @@
         };
     }
 
+    private void updatePositionByCapability(boolean forceInvalidate) {
+        final FingerprintSensorPropertiesInternal fpProp = Utils.findFirstSensorProperties(
+                mFpProps, mConfig.mSensorIds);
+        final FaceSensorPropertiesInternal faceProp = Utils.findFirstSensorProperties(
+                mFaceProps, mConfig.mSensorIds);
+        if (fpProp != null && fpProp.isAnyUdfpsType()) {
+            maybeUpdatePositionForUdfps(forceInvalidate /* invalidate */);
+        }
+        if (faceProp != null && mBiometricView.isFaceOnly()) {
+            alwaysUpdatePositionAtScreenBottom(forceInvalidate /* invalidate */);
+        }
+        if (fpProp != null && fpProp.sensorType == TYPE_POWER_BUTTON) {
+            alwaysUpdatePositionAtScreenBottom(forceInvalidate /* invalidate */);
+        }
+    }
+
     private static boolean shouldUpdatePositionForUdfps(@NonNull View view) {
         if (view instanceof BiometricPromptLayout) {
             // this will force the prompt to align itself on the edge of the screen
@@ -627,11 +654,14 @@
         if (display == null) {
             return false;
         }
+
+        final DisplayInfo cachedDisplayInfo = new DisplayInfo();
+        display.getDisplayInfo(cachedDisplayInfo);
         if (mBiometricView == null || !shouldUpdatePositionForUdfps(mBiometricView.asView())) {
             return false;
         }
 
-        final int displayRotation = display.getRotation();
+        final int displayRotation = cachedDisplayInfo.rotation;
         switch (displayRotation) {
             case Surface.ROTATION_0:
                 mPanelController.setPosition(AuthPanelController.POSITION_BOTTOM);
@@ -663,6 +693,38 @@
         return true;
     }
 
+    private boolean alwaysUpdatePositionAtScreenBottom(boolean invalidate) {
+        final Display display = getDisplay();
+        if (display == null) {
+            return false;
+        }
+        if (mBiometricView == null || !shouldUpdatePositionForUdfps(mBiometricView.asView())) {
+            return false;
+        }
+
+        final int displayRotation = display.getRotation();
+        switch (displayRotation) {
+            case Surface.ROTATION_0:
+            case Surface.ROTATION_90:
+            case Surface.ROTATION_270:
+            case Surface.ROTATION_180:
+                mPanelController.setPosition(AuthPanelController.POSITION_BOTTOM);
+                setScrollViewGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
+                break;
+            default:
+                Log.e(TAG, "Unsupported display rotation: " + displayRotation);
+                mPanelController.setPosition(AuthPanelController.POSITION_BOTTOM);
+                setScrollViewGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
+                break;
+        }
+
+        if (invalidate) {
+            mPanelView.invalidateOutline();
+        }
+
+        return true;
+    }
+
     private void setScrollViewGravity(int gravity) {
         final FrameLayout.LayoutParams params =
                 (FrameLayout.LayoutParams) mBiometricScrollView.getLayoutParams();
@@ -819,6 +881,9 @@
 
         final Runnable endActionRunnable = () -> {
             setVisibility(View.INVISIBLE);
+            if (Flags.customBiometricPrompt()) {
+                mPromptSelectorInteractorProvider.get().resetPrompt();
+            }
             removeWindowIfAttached();
         };
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index 921e395..16865ca 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -31,6 +31,7 @@
 import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
 import android.os.Build
 import android.os.RemoteException
+import android.os.Trace
 import android.provider.Settings
 import android.util.Log
 import android.util.RotationUtils
@@ -58,9 +59,9 @@
 import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.power.domain.interactor.PowerInteractor
-import com.android.systemui.power.shared.model.WakefulnessState
 import com.android.systemui.res.R
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.LockscreenShadeTransitionController
@@ -125,11 +126,15 @@
         private val powerInteractor: PowerInteractor,
         @Application private val scope: CoroutineScope,
 ) {
-    private val isFinishedGoingToSleep: Flow<Unit> =
-        powerInteractor.detailedWakefulness
-            .filter { it.internalWakefulnessState == WakefulnessState.ASLEEP }
+    private val currentStateUpdatedToOffAodOrDozing: Flow<Unit> =
+        transitionInteractor.currentKeyguardState
+            .filter {
+                it == KeyguardState.OFF ||
+                    it == KeyguardState.AOD ||
+                    it == KeyguardState.DOZING
+            }
             .map { } // map to Unit
-    private var listenForAsleepJob: Job? = null
+    private var listenForCurrentKeyguardState: Job? = null
     private var addViewRunnable: Runnable? = null
     private var overlayViewLegacy: UdfpsView? = null
         private set
@@ -280,18 +285,19 @@
     private fun addViewNowOrLater(view: View, animation: UdfpsAnimationViewController<*>?) {
         if (udfpsViewPerformance()) {
             addViewRunnable = kotlinx.coroutines.Runnable {
+                Trace.setCounter("UdfpsAddView", 1)
                 windowManager.addView(
                         view,
                         coreLayoutParams.updateDimensions(animation)
                 )
             }
-            if (powerInteractor.detailedWakefulness.value.internalWakefulnessState
-                    != WakefulnessState.STARTING_TO_SLEEP) {
+            if (powerInteractor.detailedWakefulness.value.isAwake()) {
+                // Device is awake, so we add the view immediately.
                 addViewIfPending()
             } else {
-                listenForAsleepJob?.cancel()
-                listenForAsleepJob = scope.launch {
-                    isFinishedGoingToSleep.collect {
+                listenForCurrentKeyguardState?.cancel()
+                listenForCurrentKeyguardState = scope.launch {
+                    currentStateUpdatedToOffAodOrDozing.collect {
                         addViewIfPending()
                     }
                 }
@@ -306,7 +312,7 @@
 
     private fun addViewIfPending() {
         addViewRunnable?.let {
-            listenForAsleepJob?.cancel()
+            listenForCurrentKeyguardState?.cancel()
             it.run()
         }
         addViewRunnable = null
@@ -412,7 +418,14 @@
             udfpsDisplayModeProvider.disable(null)
         }
         getTouchOverlay()?.apply {
-            windowManager.removeView(this)
+            if (udfpsViewPerformance()) {
+                if (this.parent != null) {
+                    windowManager.removeView(this)
+                }
+                Trace.setCounter("UdfpsAddView", 0)
+            } else {
+                windowManager.removeView(this)
+            }
             setOnTouchListener(null)
             setOnHoverListener(null)
             overlayTouchListener?.let {
@@ -423,7 +436,7 @@
         overlayViewLegacy = null
         overlayTouchView = null
         overlayTouchListener = null
-        listenForAsleepJob?.cancel()
+        listenForCurrentKeyguardState?.cancel()
 
         return wasShowing
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
index c8fb044..8e5a97b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.biometrics.data.repository
 
 import android.content.Context
+import android.util.DisplayMetrics
 import android.util.Size
 import android.view.DisplayInfo
 import com.android.systemui.biometrics.shared.model.DisplayRotation
@@ -29,8 +30,10 @@
 import com.android.systemui.display.data.repository.DisplayRepository
 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.distinctUntilChanged
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
 
@@ -53,6 +56,9 @@
 
     /** Provides the current display size */
     val currentDisplaySize: StateFlow<Size>
+
+    /** Provides whether the current display is large screen */
+    val isLargeScreen: Flow<Boolean>
 }
 
 @SysUISingleton
@@ -121,6 +127,15 @@
                     ),
             )
 
+    override val isLargeScreen: Flow<Boolean> =
+        currentDisplayInfo
+            .map {
+                // TODO: This works, but investigate better way to handle this
+                it.logicalWidth * 160 / it.logicalDensityDpi > DisplayMetrics.DENSITY_XXXHIGH &&
+                    it.logicalHeight * 160 / it.logicalDensityDpi > DisplayMetrics.DENSITY_XXHIGH
+            }
+            .distinctUntilChanged()
+
     companion object {
         const val TAG = "DisplayStateRepositoryImpl"
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt
index ae1539e..59b59bf 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt
@@ -50,6 +50,7 @@
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.withContext
@@ -64,13 +65,16 @@
 
     /** The current face sensor location in current device rotation */
     val sensorLocation: StateFlow<Point?>
+
+    /** The info of current available camera. */
+    val cameraInfo: StateFlow<CameraInfo?>
 }
 
 /** Describes a biometric sensor */
 data class FaceSensorInfo(val id: Int, val strength: SensorStrength)
 
 /** Data class for camera info */
-private data class CameraInfo(
+data class CameraInfo(
     /** The logical id of the camera */
     val cameraId: String,
     /** The physical id of the camera */
@@ -124,7 +128,7 @@
     private val cameraInfoList: List<CameraInfo> = loadCameraInfoList()
     private var currentPhysicalCameraId: String? = null
 
-    private val defaultSensorLocation: StateFlow<Point?> =
+    override val cameraInfo: StateFlow<CameraInfo?> =
         ConflatedCallbackFlow.conflatedCallbackFlow {
                 val callback =
                     object : CameraManager.AvailabilityCallback() {
@@ -142,7 +146,7 @@
                                     physicalCameraId == it.cameraPhysicalId
                                 }
                             trySendWithFailureLogging(
-                                cameraInfo?.cameraLocation,
+                                cameraInfo,
                                 TAG,
                                 "Update face sensor location to $cameraInfo."
                             )
@@ -168,7 +172,7 @@
                                     }
                                 currentPhysicalCameraId = cameraInfo?.cameraPhysicalId
                                 trySendWithFailureLogging(
-                                    cameraInfo?.cameraLocation,
+                                    cameraInfo,
                                     TAG,
                                     "Update face sensor location to $cameraInfo."
                                 )
@@ -181,8 +185,16 @@
             .stateIn(
                 applicationScope,
                 started = SharingStarted.WhileSubscribed(),
-                initialValue =
-                    if (cameraInfoList.isNotEmpty()) cameraInfoList[0].cameraLocation else null
+                initialValue = if (cameraInfoList.isNotEmpty()) cameraInfoList[0] else null
+            )
+
+    private val defaultSensorLocation: StateFlow<Point?> =
+        cameraInfo
+            .map { it?.cameraLocation }
+            .stateIn(
+                applicationScope,
+                started = SharingStarted.WhileSubscribed(),
+                initialValue = null
             )
 
     override val sensorLocation: StateFlow<Point?> =
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
index 435df5f..0c0ed77 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
@@ -51,8 +51,6 @@
  * There is never more than one instance of the FingerprintProperty at any given time.
  */
 interface FingerprintPropertyRepository {
-    /** Whether the fingerprint properties have been initialized yet. */
-    val propertiesInitialized: StateFlow<Boolean>
 
     /** The id of fingerprint sensor. */
     val sensorId: Flow<Int>
@@ -107,16 +105,7 @@
             .stateIn(
                 applicationScope,
                 started = SharingStarted.Eagerly,
-                initialValue = UNINITIALIZED_PROPS,
-            )
-
-    override val propertiesInitialized: StateFlow<Boolean> =
-        props
-            .map { it != UNINITIALIZED_PROPS }
-            .stateIn(
-                applicationScope,
-                started = SharingStarted.WhileSubscribed(),
-                initialValue = props.value != UNINITIALIZED_PROPS,
+                initialValue = DEFAULT_PROPS,
             )
 
     override val sensorId: Flow<Int> = props.map { it.sensorId }
@@ -135,17 +124,6 @@
 
     companion object {
         private const val TAG = "FingerprintPropertyRepositoryImpl"
-        private val UNINITIALIZED_PROPS =
-            FingerprintSensorPropertiesInternal(
-                -2 /* sensorId */,
-                SensorProperties.STRENGTH_CONVENIENCE,
-                0 /* maxEnrollmentsPerUser */,
-                listOf<ComponentInfoInternal>(),
-                FingerprintSensorProperties.TYPE_UNKNOWN,
-                false /* halControlsIllumination */,
-                true /* resetLockoutRequiresHardwareAuthToken */,
-                listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT)
-            )
         private val DEFAULT_PROPS =
             FingerprintSensorPropertiesInternal(
                 -1 /* sensorId */,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt
index ad7bb0e..b87fadf 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt
@@ -16,8 +16,11 @@
 
 package com.android.systemui.biometrics.data.repository
 
+import android.hardware.biometrics.Flags
 import android.hardware.biometrics.PromptInfo
 import com.android.systemui.biometrics.AuthController
+import com.android.systemui.biometrics.Utils
+import com.android.systemui.biometrics.Utils.isDeviceCredentialAllowed
 import com.android.systemui.biometrics.shared.model.PromptKind
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -65,6 +68,18 @@
      */
     val isConfirmationRequired: Flow<Boolean>
 
+    /**
+     * If biometric prompt without icon needs to show for displaying content prior to credential
+     * view.
+     */
+    val showBpWithoutIconForCredential: StateFlow<Boolean>
+
+    /**
+     * Update whether biometric prompt without icon needs to show for displaying content prior to
+     * credential view, which should be set before [setPrompt].
+     */
+    fun setShouldShowBpWithoutIconForCredential(promptInfo: PromptInfo)
+
     /** Update the prompt configuration, which should be set before [isShowing]. */
     fun setPrompt(
         promptInfo: PromptInfo,
@@ -129,6 +144,19 @@
             }
             .distinctUntilChanged()
 
+    private val _showBpWithoutIconForCredential: MutableStateFlow<Boolean> = MutableStateFlow(false)
+    override val showBpWithoutIconForCredential = _showBpWithoutIconForCredential.asStateFlow()
+
+    override fun setShouldShowBpWithoutIconForCredential(promptInfo: PromptInfo) {
+        val hasCredentialViewShown = kind.value !is PromptKind.Biometric
+        val showBpForCredential =
+            Flags.customBiometricPrompt() &&
+                !Utils.isBiometricAllowed(promptInfo) &&
+                isDeviceCredentialAllowed(promptInfo) &&
+                promptInfo.contentView != null
+        _showBpWithoutIconForCredential.value = showBpForCredential && !hasCredentialViewShown
+    }
+
     override fun setPrompt(
         promptInfo: PromptInfo,
         userId: Int,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt
index 427361d..7d67219 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt
@@ -68,6 +68,8 @@
 
     /** Called on configuration changes, used to keep the display state in sync */
     fun onConfigurationChanged(newConfig: Configuration)
+
+    val isLargeScreen: Flow<Boolean>
 }
 
 /** Encapsulates logic for interacting with the display state. */
@@ -138,6 +140,8 @@
             .sample(defaultDisplay)
             .map { it?.state == Display.STATE_OFF }
 
+    override val isLargeScreen: Flow<Boolean> = displayStateRepository.isLargeScreen
+
     companion object {
         private const val TAG = "DisplayStateInteractor"
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
index 8bc0c54..ff9cdbd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt
@@ -25,7 +25,6 @@
 import com.android.systemui.dagger.qualifiers.Application
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.filterNotNull
@@ -40,7 +39,6 @@
     configurationInteractor: ConfigurationInteractor,
     displayStateInteractor: DisplayStateInteractor,
 ) {
-    val propertiesInitialized: StateFlow<Boolean> = repository.propertiesInitialized
     val isUdfps: Flow<Boolean> = repository.sensorType.map { it.isUdfps() }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt
index e3facff..94cea57 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt
@@ -30,6 +30,7 @@
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
@@ -59,6 +60,13 @@
     /** If the prompt is currently showing. */
     val isShowing: Flow<Boolean> = biometricPromptRepository.isShowing
 
+    /**
+     * If biometric prompt without icon needs to show for displaying content prior to credential
+     * view.
+     */
+    val showBpWithoutIconForCredential: StateFlow<Boolean> =
+        biometricPromptRepository.showBpWithoutIconForCredential
+
     /** Metadata about the current credential prompt, including app-supplied preferences. */
     val prompt: Flow<BiometricPromptRequest.Credential?> =
         combine(
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
index b3f9574..45816c1 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.map
@@ -70,6 +71,18 @@
     /** Fingerprint sensor type */
     val sensorType: Flow<FingerprintSensorType>
 
+    /**
+     * If biometric prompt without icon needs to show for displaying content prior to credential
+     * view.
+     */
+    val showBpWithoutIconForCredential: StateFlow<Boolean>
+
+    /**
+     * Update whether biometric prompt without icon needs to show for displaying content prior to
+     * credential view, which should be set before [PromptRepository.setPrompt].
+     */
+    fun setShouldShowBpWithoutIconForCredential(promptInfo: PromptInfo)
+
     /** Use biometrics for authentication. */
     fun useBiometricsForAuthentication(
         promptInfo: PromptInfo,
@@ -154,6 +167,12 @@
 
     override val sensorType: Flow<FingerprintSensorType> = fingerprintPropertyRepository.sensorType
 
+    override val showBpWithoutIconForCredential = promptRepository.showBpWithoutIconForCredential
+
+    override fun setShouldShowBpWithoutIconForCredential(promptInfo: PromptInfo) {
+        promptRepository.setShouldShowBpWithoutIconForCredential(promptInfo)
+    }
+
     override fun useBiometricsForAuthentication(
         promptInfo: PromptInfo,
         userId: Int,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt
index 6133a51c..6f079e2 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt
@@ -17,6 +17,7 @@
     val title: String,
     val subtitle: String,
     val description: String,
+    val contentView: PromptContentView?,
     val userInfo: BiometricUserInfo,
     val operationInfo: BiometricOperationInfo,
     val showEmergencyCallButton: Boolean,
@@ -33,11 +34,11 @@
             title = info.title?.toString() ?: "",
             subtitle = info.subtitle?.toString() ?: "",
             description = info.description?.toString() ?: "",
+            contentView = info.contentView,
             userInfo = userInfo,
             operationInfo = operationInfo,
             showEmergencyCallButton = info.isShowEmergencyCallButton
         ) {
-        val contentView: PromptContentView? = info.contentView
         val logoRes: Int = info.logoRes
         val logoBitmap: Bitmap? = info.logoBitmap
         val logoDescription: String? = info.logoDescription
@@ -54,6 +55,7 @@
             title = (info.deviceCredentialTitle ?: info.title)?.toString() ?: "",
             subtitle = (info.deviceCredentialSubtitle ?: info.subtitle)?.toString() ?: "",
             description = (info.deviceCredentialDescription ?: info.description)?.toString() ?: "",
+            contentView = info.contentView,
             userInfo = userInfo,
             operationInfo = operationInfo,
             showEmergencyCallButton = info.isShowEmergencyCallButton
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricCustomizedViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricCustomizedViewBinder.kt
index 96582cb..e58c8ff 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricCustomizedViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricCustomizedViewBinder.kt
@@ -31,7 +31,6 @@
 import android.view.LayoutInflater
 import android.view.View
 import android.widget.LinearLayout
-import android.widget.ScrollView
 import android.widget.Space
 import android.widget.TextView
 import androidx.lifecycle.Lifecycle
@@ -46,7 +45,7 @@
 
 /** Sub-binder for [BiometricPromptLayout.customized_view_container]. */
 object BiometricCustomizedViewBinder {
-    fun bind(customizedViewContainer: ScrollView, spaceAbove: Space, viewModel: PromptViewModel) {
+    fun bind(customizedViewContainer: LinearLayout, spaceAbove: Space, viewModel: PromptViewModel) {
         customizedViewContainer.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.CREATED) {
                 launch {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index cd5b124..e48f05d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -22,7 +22,6 @@
 import android.hardware.biometrics.BiometricAuthenticator
 import android.hardware.biometrics.BiometricConstants
 import android.hardware.biometrics.BiometricPrompt
-import android.hardware.biometrics.Flags.customBiometricPrompt
 import android.hardware.face.FaceManager
 import android.text.method.ScrollingMovementMethod
 import android.util.Log
@@ -33,7 +32,7 @@
 import android.view.accessibility.AccessibilityManager
 import android.widget.Button
 import android.widget.ImageView
-import android.widget.ScrollView
+import android.widget.LinearLayout
 import android.widget.TextView
 import androidx.lifecycle.DefaultLifecycleObserver
 import androidx.lifecycle.Lifecycle
@@ -101,7 +100,7 @@
         val subtitleView = view.requireViewById<TextView>(R.id.subtitle)
         val descriptionView = view.requireViewById<TextView>(R.id.description)
         val customizedViewContainer =
-            view.requireViewById<ScrollView>(R.id.customized_view_container)
+            view.requireViewById<LinearLayout>(R.id.customized_view_container)
 
         // set selected to enable marquee unless a screen reader is enabled
         logoView.isSelected =
@@ -119,7 +118,7 @@
 
         val iconSizeOverride =
             if (constraintBp()) {
-                viewModel.fingerprintAffordanceSize
+                null
             } else {
                 (view as BiometricPromptLayout).updatedFingerprintAffordanceSize
             }
@@ -151,17 +150,6 @@
             // these do not change and need to be set before any size transitions
             val modalities = viewModel.modalities.first()
 
-            // If there is no biometrics available, biometric prompt is showing just for displaying
-            // content, no authentication needed.
-            if (!(customBiometricPrompt() && modalities.isEmpty)) {
-                PromptIconViewBinder.bind(
-                    iconView,
-                    iconOverlayView,
-                    iconSizeOverride,
-                    viewModel,
-                )
-            }
-
             if (modalities.hasFingerprint) {
                 /**
                  * Load the given [rawResources] immediately so they are cached for use in the
@@ -233,6 +221,19 @@
                 )
             }
 
+            lifecycleScope.launch {
+                viewModel.showBpWithoutIconForCredential.collect {
+                    if (!it) {
+                        PromptIconViewBinder.bind(
+                            iconView,
+                            iconOverlayView,
+                            iconSizeOverride,
+                            viewModel,
+                        )
+                    }
+                }
+            }
+
             // TODO(b/251476085): migrate legacy icon controllers and remove
             // The fingerprint sensor is started by the legacy
             // AuthContainerView#onDialogAnimatedIn in all cases but the implicit coex flow
@@ -651,6 +652,8 @@
 
     fun isCoex() = modalities.hasFaceAndFingerprint
 
+    fun isFaceOnly() = modalities.hasFaceOnly
+
     fun asView() = view
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
index a37d916..478ef8f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
@@ -21,7 +21,6 @@
 import android.animation.ValueAnimator
 import android.graphics.Outline
 import android.graphics.Rect
-import android.hardware.biometrics.Flags
 import android.transition.AutoTransition
 import android.transition.TransitionManager
 import android.view.Surface
@@ -55,6 +54,7 @@
 import com.android.systemui.biometrics.ui.viewmodel.isRight
 import com.android.systemui.biometrics.ui.viewmodel.isSmall
 import com.android.systemui.biometrics.ui.viewmodel.isTop
+import com.android.systemui.keyguard.ui.view.layout.sections.setVisibility
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.res.R
 import kotlin.math.abs
@@ -100,6 +100,8 @@
             val leftGuideline = view.requireViewById<Guideline>(R.id.leftGuideline)
             val rightGuideline = view.requireViewById<Guideline>(R.id.rightGuideline)
             val bottomGuideline = view.requireViewById<Guideline>(R.id.bottomGuideline)
+            val topGuideline = view.requireViewById<Guideline>(R.id.topGuideline)
+            val midGuideline = view.findViewById<Guideline>(R.id.midGuideline)
 
             val iconHolderView = view.requireViewById<View>(R.id.biometric_icon)
             val panelView = view.requireViewById<View>(R.id.panel)
@@ -111,18 +113,30 @@
 
             val smallConstraintSet = ConstraintSet()
             smallConstraintSet.clone(mediumConstraintSet)
-            viewsToHideWhenSmall.forEach { smallConstraintSet.setVisibility(it.id, View.GONE) }
 
             val largeConstraintSet = ConstraintSet()
             largeConstraintSet.clone(mediumConstraintSet)
-            viewsToHideWhenSmall.forEach { largeConstraintSet.setVisibility(it.id, View.GONE) }
-            largeConstraintSet.setVisibility(iconHolderView.id, View.GONE)
-            largeConstraintSet.setVisibility(R.id.biometric_icon_overlay, View.GONE)
-            largeConstraintSet.setVisibility(R.id.indicator, View.GONE)
             largeConstraintSet.setGuidelineBegin(leftGuideline.id, 0)
             largeConstraintSet.setGuidelineEnd(rightGuideline.id, 0)
             largeConstraintSet.setGuidelineEnd(bottomGuideline.id, 0)
 
+            // TODO: Investigate better way to handle 180 rotations
+            val flipConstraintSet = ConstraintSet()
+            flipConstraintSet.clone(mediumConstraintSet)
+            flipConstraintSet.connect(
+                R.id.scrollView,
+                ConstraintSet.START,
+                R.id.midGuideline,
+                ConstraintSet.START
+            )
+            flipConstraintSet.connect(
+                R.id.scrollView,
+                ConstraintSet.END,
+                R.id.rightGuideline,
+                ConstraintSet.END
+            )
+            flipConstraintSet.setHorizontalBias(R.id.biometric_icon, .2f)
+
             // Round the panel outline
             panelView.outlineProvider =
                 object : ViewOutlineProvider() {
@@ -138,70 +152,51 @@
                         .getInsets(WindowInsets.Type.navigationBars())
                         .bottom
 
+                // TODO: Move to viewmodel
                 fun measureBounds(position: PromptPosition) {
-                    val width = min(windowBounds.height(), windowBounds.width())
+                    val density = windowManager.currentWindowMetrics.density
+                    val width = min((640 * density).toInt(), windowBounds.width())
 
                     var left = -1
-                    var top = -1
                     var right = -1
                     var bottom = -1
+                    var mid = -1
 
                     when {
                         position.isTop -> {
                             left = windowBounds.centerX() - width / 2 + viewModel.promptMargin
-                            top = viewModel.promptMargin
                             right = windowBounds.centerX() - width / 2 + viewModel.promptMargin
                             bottom = iconHolderView.centerY() * 2 - iconHolderView.centerY() / 4
                         }
                         position.isBottom -> {
-                            if (view.isLandscape()) {
-                                left = windowBounds.centerX() - width / 2 + viewModel.promptMargin
-                                top = iconHolderView.centerY()
-                                right = windowBounds.centerX() - width / 2 + viewModel.promptMargin
-                                bottom = bottomInset + viewModel.promptMargin
-                            } else {
-                                left = windowBounds.centerX() - width / 2 + viewModel.promptMargin
-                                top =
-                                    windowBounds.height() -
-                                        (windowBounds.height() - iconHolderView.centerY()) * 2 +
-                                        viewModel.promptMargin
-                                right = windowBounds.centerX() - width / 2 + viewModel.promptMargin
-                                bottom = viewModel.promptMargin
-                            }
+                            left = windowBounds.centerX() - width / 2 + viewModel.promptMargin
+                            right = windowBounds.centerX() - width / 2 + viewModel.promptMargin
+                            bottom = viewModel.promptMargin
                         }
-
-                        // For Udfps exclusive left and right, measure guideline to center
-                        // icon in BP
                         position.isLeft -> {
                             left = viewModel.promptMargin
-                            top =
-                                windowBounds.height() -
-                                    (windowBounds.height() - iconHolderView.centerY()) * 2 +
-                                    viewModel.promptMargin
-                            right =
+                            mid =
                                 abs(
                                     windowBounds.width() - iconHolderView.centerX() * 2 +
                                         viewModel.promptMargin
                                 )
+                            right = windowBounds.width() - (windowBounds.width() * .85).toInt()
                             bottom = bottomInset + viewModel.promptMargin
                         }
                         position.isRight -> {
-                            left =
+                            left = windowBounds.width() - (windowBounds.width() * .85).toInt()
+                            right = viewModel.promptMargin
+                            bottom = bottomInset + viewModel.promptMargin
+                            mid =
                                 abs(
                                     iconHolderView.centerX() -
                                         (windowBounds.width() - iconHolderView.centerX()) -
                                         viewModel.promptMargin
                                 )
-                            top =
-                                windowBounds.height() -
-                                    (windowBounds.height() - iconHolderView.centerY()) * 2 +
-                                    viewModel.promptMargin
-                            right = viewModel.promptMargin
-                            bottom = bottomInset + viewModel.promptMargin
                         }
                     }
 
-                    val bounds = Rect(left, top, right, bottom)
+                    val bounds = Rect(left, mid, right, bottom)
                     if (bounds.shouldAdjustLeftGuideline()) {
                         leftGuideline.setGuidelineBegin(bounds.left)
                         smallConstraintSet.setGuidelineBegin(leftGuideline.id, bounds.left)
@@ -217,15 +212,32 @@
                         smallConstraintSet.setGuidelineEnd(bottomGuideline.id, bounds.bottom)
                         mediumConstraintSet.setGuidelineEnd(bottomGuideline.id, bounds.bottom)
                     }
+
+                    if (position.isBottom) {
+                        topGuideline.setGuidelinePercent(.25f)
+                        mediumConstraintSet.setGuidelinePercent(topGuideline.id, .25f)
+                    } else {
+                        topGuideline.setGuidelinePercent(0f)
+                        mediumConstraintSet.setGuidelinePercent(topGuideline.id, 0f)
+                    }
+
+                    if (mid != -1 && midGuideline != null) {
+                        midGuideline.setGuidelineBegin(mid)
+                    }
                 }
 
-                view.repeatWhenAttached {
-                    var currentSize: PromptSize? = null
-                    val modalities = viewModel.modalities.first()
-                    // TODO(b/288175072): Move all visibility settings together.
-                    //  If there is no biometrics available, biometric prompt is showing just for
-                    // displaying content, no authentication needed.
-                    if (Flags.customBiometricPrompt() && modalities.isEmpty) {
+                fun setConstraintSetVisibility() {
+                    viewsToHideWhenSmall.forEach {
+                        mediumConstraintSet.setVisibility(it.id, it.showContentOrHide())
+                        largeConstraintSet.setVisibility(it.id, View.GONE)
+                        smallConstraintSet.setVisibility(it.id, View.GONE)
+                    }
+
+                    largeConstraintSet.setVisibility(iconHolderView.id, View.GONE)
+                    largeConstraintSet.setVisibility(R.id.biometric_icon_overlay, View.GONE)
+                    largeConstraintSet.setVisibility(R.id.indicator, View.GONE)
+
+                    if (viewModel.showBpWithoutIconForCredential.value) {
                         smallConstraintSet.setVisibility(iconHolderView.id, View.GONE)
                         smallConstraintSet.setVisibility(R.id.biometric_icon_overlay, View.GONE)
                         smallConstraintSet.setVisibility(R.id.indicator, View.GONE)
@@ -233,12 +245,23 @@
                         mediumConstraintSet.setVisibility(R.id.biometric_icon_overlay, View.GONE)
                         mediumConstraintSet.setVisibility(R.id.indicator, View.GONE)
                     }
+                }
+
+                view.repeatWhenAttached {
+                    var currentSize: PromptSize? = null
+
                     lifecycleScope.launch {
                         combine(viewModel.position, viewModel.size, ::Pair).collect {
                             (position, size) ->
                             view.doOnAttach {
-                                measureBounds(position)
+                                if (position.isLeft) {
+                                    flipConstraintSet.applyTo(view)
+                                } else if (position.isRight) {
+                                    mediumConstraintSet.applyTo(view)
+                                }
 
+                                measureBounds(position)
+                                setConstraintSetVisibility()
                                 when {
                                     size.isSmall -> {
                                         val ratio =
@@ -313,7 +336,6 @@
                 // TODO(b/251476085): migrate the legacy panel controller and simplify this
                 view.repeatWhenAttached {
                     var currentSize: PromptSize? = null
-                    val modalities = viewModel.modalities.first()
                     lifecycleScope.launch {
                         /**
                          * View is only set visible in BiometricViewSizeBinder once PromptSize is
@@ -331,11 +353,13 @@
 
                             // prepare for animated size transitions
                             for (v in viewsToHideWhenSmall) {
-                                v.showContentOrHide(forceHide = size.isSmall)
+                                v.visibility = v.showContentOrHide(forceHide = size.isSmall)
                             }
-                            if (Flags.customBiometricPrompt() && modalities.isEmpty) {
+
+                            if (viewModel.showBpWithoutIconForCredential.value) {
                                 iconHolderView.visibility = View.GONE
                             }
+
                             if (currentSize == null && size.isSmall) {
                                 iconHolderView.alpha = 0f
                             }
@@ -344,9 +368,9 @@
                             }
 
                             // TODO(b/302735104): Fix wrong height due to the delay of
-                            // PromptContentView. addOnLayoutChangeListener() will cause crash when
-                            // showing credential view, since |PromptIconViewModel| won't release
-                            // the flow.
+                            // PromptContentView. addOnLayoutChangeListener() will cause crash
+                            // when showing credential view, since |PromptIconViewModel| won't
+                            // release the flow.
                             // propagate size changes to legacy panel controller and animate
                             // transitions
                             view.doOnLayout {
@@ -456,19 +480,24 @@
 }
 
 private fun View.isLandscape(): Boolean {
-    val r = context.display?.rotation
-    return r == Surface.ROTATION_90 || r == Surface.ROTATION_270
+    val r = context.display.rotation
+    return if (
+        context.resources.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)
+    ) {
+        r == Surface.ROTATION_0 || r == Surface.ROTATION_180
+    } else {
+        r == Surface.ROTATION_90 || r == Surface.ROTATION_270
+    }
 }
 
-private fun View.showContentOrHide(forceHide: Boolean = false) {
+private fun View.showContentOrHide(forceHide: Boolean = false): Int {
     val isTextViewWithBlankText = this is TextView && this.text.isBlank()
     val isImageViewWithoutImage = this is ImageView && this.drawable == null
-    visibility =
-        if (forceHide || isTextViewWithBlankText || isImageViewWithoutImage) {
-            View.GONE
-        } else {
-            View.VISIBLE
-        }
+    return if (forceHide || isTextViewWithBlankText || isImageViewWithoutImage) {
+        View.GONE
+    } else {
+        View.VISIBLE
+    }
 }
 
 private fun View.centerX(): Int {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt
index 2e47375..3469cfa 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt
@@ -37,6 +37,7 @@
 import com.android.systemui.util.kotlin.Utils.Companion.toTriple
 import com.android.systemui.util.kotlin.sample
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.launch
 
 /** Sub-binder for [BiometricPromptLayout.iconView]. */
@@ -62,6 +63,12 @@
 
                     iconOverlayView.layoutParams.width = iconViewLayoutParamSizeOverride.first
                     iconOverlayView.layoutParams.height = iconViewLayoutParamSizeOverride.second
+                } else {
+                    iconView.layoutParams.width = viewModel.fingerprintIconWidth.first()
+                    iconView.layoutParams.height = viewModel.fingerprintIconWidth.first()
+
+                    iconOverlayView.layoutParams.width = viewModel.fingerprintIconWidth.first()
+                    iconOverlayView.layoutParams.height = viewModel.fingerprintIconWidth.first()
                 }
 
                 var faceIcon: AnimatedVectorDrawable? = null
@@ -77,15 +84,12 @@
                     }
 
                 launch {
-                    var width: Int
-                    var height: Int
+                    var width = 0
+                    var height = 0
                     viewModel.activeAuthType.collect { activeAuthType ->
                         when (activeAuthType) {
                             AuthType.Fingerprint,
                             AuthType.Coex -> {
-                                width = viewModel.fingerprintIconWidth
-                                height = viewModel.fingerprintIconHeight
-
                                 /**
                                  * View is only set visible in BiometricViewSizeBinder once
                                  * PromptSize is determined that accounts for iconView size, to
@@ -113,7 +117,7 @@
                             }
                         }
 
-                        if (iconViewLayoutParamSizeOverride == null) {
+                        if (width != 0 && height != 0) {
                             iconView.layoutParams.width = width
                             iconView.layoutParams.height = height
                             iconOverlayView.layoutParams.width = width
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt
index 03c5c53..46be8c7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt
@@ -4,13 +4,13 @@
 import android.graphics.drawable.Drawable
 import android.text.InputType
 import com.android.internal.widget.LockPatternView
-import com.android.systemui.res.R
 import com.android.systemui.biometrics.Utils
 import com.android.systemui.biometrics.domain.interactor.CredentialStatus
 import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor
 import com.android.systemui.biometrics.domain.model.BiometricPromptRequest
 import com.android.systemui.biometrics.shared.model.BiometricUserInfo
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.res.R
 import javax.inject.Inject
 import kotlin.reflect.KClass
 import kotlinx.coroutines.flow.Flow
@@ -32,14 +32,16 @@
 
     /** Top level information about the prompt. */
     val header: Flow<CredentialHeaderViewModel> =
-        credentialInteractor.prompt.filterIsInstance<BiometricPromptRequest.Credential>().map {
-            request ->
+        combine(
+            credentialInteractor.prompt.filterIsInstance<BiometricPromptRequest.Credential>(),
+            credentialInteractor.showBpWithoutIconForCredential
+        ) { request, showBpWithoutIconForCredential ->
             BiometricPromptHeaderViewModelImpl(
                 request,
                 user = request.userInfo,
                 title = request.title,
-                subtitle = request.subtitle,
-                description = request.description,
+                subtitle = if (showBpWithoutIconForCredential) "" else request.subtitle,
+                description = if (showBpWithoutIconForCredential) "" else request.description,
                 icon = applicationContext.asLockIcon(request.userInfo.deviceCredentialOwnerId),
                 showEmergencyCallButton = request.showEmergencyCallButton
             )
@@ -145,7 +147,7 @@
                 .createLaunchEmergencyDialerIntent(null)
                 .setFlags(
                     android.content.Intent.FLAG_ACTIVITY_NEW_TASK or
-                            android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP
+                        android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP
                 )
         context.startActivity(intent)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptIconViewModel.kt
index b7cffaf..257eb4a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptIconViewModel.kt
@@ -159,8 +159,8 @@
     val lastPulseLightToDark: Flow<Boolean> = _lastPulseLightToDark.asStateFlow()
 
     /** Layout params for fingerprint iconView */
-    val fingerprintIconWidth: Int = promptViewModel.fingerprintIconWidth
-    val fingerprintIconHeight: Int = promptViewModel.fingerprintIconHeight
+    val fingerprintIconWidth: Flow<Int> = promptViewModel.fingerprintSensorDiameter
+    val fingerprintIconHeight: Flow<Int> = promptViewModel.fingerprintSensorDiameter
 
     /** Layout params for face iconView */
     val faceIconWidth: Int = promptViewModel.faceIconWidth
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 c933e0e..61aeffe 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
@@ -47,6 +47,7 @@
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asSharedFlow
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.combine
@@ -84,14 +85,15 @@
     val faceIconHeight: Int =
         context.resources.getDimensionPixelSize(R.dimen.biometric_dialog_face_icon_size)
 
-    val fingerprintSensorDiameter: Int =
-        (udfpsOverlayInteractor.udfpsOverlayParams.value.sensorBounds.width() *
-                udfpsOverlayInteractor.udfpsOverlayParams.value.scaleFactor)
-            .toInt()
-    val fingerprintAffordanceSize: Pair<Int, Int>? =
-        if (fingerprintSensorDiameter != 0)
-            Pair(fingerprintSensorDiameter, fingerprintSensorDiameter)
-        else null
+    val fingerprintSensorDiameter: Flow<Int> =
+        combine(modalities, udfpsOverlayInteractor.udfpsOverlayParams) { modalities, overlayParams
+            ->
+            if (modalities.hasUdfps) {
+                overlayParams.sensorBounds.width()
+            } else {
+                fingerprintIconWidth
+            }
+        }
 
     private val _accessibilityHint = MutableSharedFlow<String>()
 
@@ -123,6 +125,9 @@
     /** The kind of credential the user has. */
     val credentialKind: Flow<PromptKind> = promptSelectorInteractor.credentialKind
 
+    val showBpWithoutIconForCredential: StateFlow<Boolean> =
+        promptSelectorInteractor.showBpWithoutIconForCredential
+
     /** The label to use for the cancel button. */
     val negativeButtonText: Flow<String> =
         promptSelectorInteractor.prompt.map { it?.negativeButtonText ?: "" }
@@ -153,12 +158,13 @@
 
     /** The current position of the prompt */
     val position: Flow<PromptPosition> =
-        combine(_forceLargeSize, modalities, displayStateInteractor.currentRotation) {
-                forceLarge,
-                modalities,
-                rotation ->
+        combine(
+                _forceLargeSize,
+                displayStateInteractor.isLargeScreen,
+                displayStateInteractor.currentRotation
+            ) { forceLarge, isLargeScreen, rotation ->
                 when {
-                    forceLarge || !modalities.hasUdfps -> PromptPosition.Bottom
+                    forceLarge || isLargeScreen -> PromptPosition.Bottom
                     rotation == DisplayRotation.ROTATION_90 -> PromptPosition.Right
                     rotation == DisplayRotation.ROTATION_270 -> PromptPosition.Left
                     rotation == DisplayRotation.ROTATION_180 -> PromptPosition.Top
@@ -340,22 +346,22 @@
     /** If the indicator (help, error) message should be shown. */
     val isIndicatorMessageVisible: Flow<Boolean> =
         combine(
-                size,
-                message,
-            ) { size, message ->
-                size.isNotSmall && message.message.isNotBlank()
-            }
-            .distinctUntilChanged()
+            size,
+            position,
+            message,
+        ) { size, _, message ->
+            size.isNotSmall && message.message.isNotBlank()
+        }
 
     /** If the auth is pending confirmation and the confirm button should be shown. */
     val isConfirmButtonVisible: Flow<Boolean> =
         combine(
-                size,
-                isPendingConfirmation,
-            ) { size, isPendingConfirmation ->
-                size.isNotSmall && isPendingConfirmation
-            }
-            .distinctUntilChanged()
+            size,
+            position,
+            isPendingConfirmation,
+        ) { size, _, isPendingConfirmation ->
+            size.isNotSmall && isPendingConfirmation
+        }
 
     /** If the icon can be used as a confirmation button. */
     val isIconConfirmButton: Flow<Boolean> = size.map { it.isNotSmall }.distinctUntilChanged()
@@ -363,28 +369,25 @@
     /** If the negative button should be shown. */
     val isNegativeButtonVisible: Flow<Boolean> =
         combine(
-                size,
-                isAuthenticated,
-                promptSelectorInteractor.isCredentialAllowed,
-            ) { size, authState, credentialAllowed ->
-                size.isNotSmall && authState.isNotAuthenticated && !credentialAllowed
-            }
-            .distinctUntilChanged()
+            size,
+            position,
+            isAuthenticated,
+            promptSelectorInteractor.isCredentialAllowed,
+        ) { size, _, authState, credentialAllowed ->
+            size.isNotSmall && authState.isNotAuthenticated && !credentialAllowed
+        }
 
     /** If the cancel button should be shown (. */
     val isCancelButtonVisible: Flow<Boolean> =
         combine(
-                size,
-                isAuthenticated,
-                isNegativeButtonVisible,
-                isConfirmButtonVisible,
-            ) { size, authState, showNegativeButton, showConfirmButton ->
-                size.isNotSmall &&
-                    authState.isAuthenticated &&
-                    !showNegativeButton &&
-                    showConfirmButton
-            }
-            .distinctUntilChanged()
+            size,
+            position,
+            isAuthenticated,
+            isNegativeButtonVisible,
+            isConfirmButtonVisible,
+        ) { size, _, authState, showNegativeButton, showConfirmButton ->
+            size.isNotSmall && authState.isAuthenticated && !showNegativeButton && showConfirmButton
+        }
 
     private val _canTryAgainNow = MutableStateFlow(false)
     /**
@@ -393,35 +396,34 @@
      */
     val canTryAgainNow: Flow<Boolean> =
         combine(
-                _canTryAgainNow,
-                size,
-                isAuthenticated,
-                isRetrySupported,
-            ) { readyToTryAgain, size, authState, supportsRetry ->
-                readyToTryAgain && size.isNotSmall && supportsRetry && authState.isNotAuthenticated
-            }
-            .distinctUntilChanged()
+            _canTryAgainNow,
+            size,
+            position,
+            isAuthenticated,
+            isRetrySupported,
+        ) { readyToTryAgain, size, _, authState, supportsRetry ->
+            readyToTryAgain && size.isNotSmall && supportsRetry && authState.isNotAuthenticated
+        }
 
     /** If the try again button show be shown (only the button, see [canTryAgainNow]). */
     val isTryAgainButtonVisible: Flow<Boolean> =
         combine(
-                canTryAgainNow,
-                modalities,
-            ) { tryAgainIsPossible, modalities ->
-                tryAgainIsPossible && modalities.hasFaceOnly
-            }
-            .distinctUntilChanged()
+            canTryAgainNow,
+            modalities,
+        ) { tryAgainIsPossible, modalities ->
+            tryAgainIsPossible && modalities.hasFaceOnly
+        }
 
     /** If the credential fallback button show be shown. */
     val isCredentialButtonVisible: Flow<Boolean> =
         combine(
-                size,
-                isAuthenticated,
-                promptSelectorInteractor.isCredentialAllowed,
-            ) { size, authState, credentialAllowed ->
-                size.isNotSmall && authState.isNotAuthenticated && credentialAllowed
-            }
-            .distinctUntilChanged()
+            size,
+            position,
+            isAuthenticated,
+            promptSelectorInteractor.isCredentialAllowed,
+        ) { size, _, authState, credentialAllowed ->
+            size.isNotSmall && authState.isNotAuthenticated && credentialAllowed
+        }
 
     private val history = PromptHistoryImpl()
     private var messageJob: Job? = null
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/SimBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/SimBouncerRepository.kt
index 269878b..b9e1c55 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/SimBouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/SimBouncerRepository.kt
@@ -92,7 +92,7 @@
     keyguardUpdateMonitor: KeyguardUpdateMonitor,
     private val subscriptionManager: SubscriptionManagerProxy,
     broadcastDispatcher: BroadcastDispatcher,
-    euiccManager: EuiccManager,
+    euiccManager: EuiccManager?,
 ) : SimBouncerRepository {
     private val isPukScreenAvailable: Boolean =
         resources.getBoolean(com.android.internal.R.bool.config_enable_puk_unlock_screen)
@@ -163,7 +163,9 @@
     @SuppressLint("MissingPermission")
     override val isLockedEsim: StateFlow<Boolean?> =
         activeSubscriptionInfo
-            .map { info -> info?.let { euiccManager.isEnabled && info.isEmbedded } }
+            .map { info ->
+                info?.let { euiccManager != null && euiccManager.isEnabled && info.isEmbedded }
+            }
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.Eagerly,
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorModule.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorModule.kt
index efa7792..0f61eef 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorModule.kt
@@ -50,7 +50,7 @@
     }
 
     @Provides
-    fun provideEuiccManager(@Application applicationContext: Context): EuiccManager {
-        return applicationContext.getSystemService(Context.EUICC_SERVICE) as EuiccManager
+    fun provideEuiccManager(@Application applicationContext: Context): EuiccManager? {
+        return applicationContext.getSystemService(Context.EUICC_SERVICE) as EuiccManager?
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/SimBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/SimBouncerInteractor.kt
index 99d1f13..c3d4cb3 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/SimBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/SimBouncerInteractor.kt
@@ -61,7 +61,7 @@
     private val telephonyManager: TelephonyManager,
     @Main private val resources: Resources,
     private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
-    private val euiccManager: EuiccManager,
+    private val euiccManager: EuiccManager?,
     // TODO(b/307977401): Replace this with `MobileConnectionsInteractor` when available.
     mobileConnectionsRepository: MobileConnectionsRepository,
 ) {
@@ -141,11 +141,13 @@
                 UserHandle.SYSTEM
             )
         applicationScope.launch(backgroundDispatcher) {
-            euiccManager.switchToSubscription(
-                INVALID_SUBSCRIPTION_ID,
-                activeSubscription.portIndex,
-                callbackIntent,
-            )
+            if (euiccManager != null) {
+                euiccManager.switchToSubscription(
+                    INVALID_SUBSCRIPTION_ID,
+                    activeSubscription.portIndex,
+                    callbackIntent,
+                )
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/shared/flag/ComposeBouncerFlags.kt b/packages/SystemUI/src/com/android/systemui/bouncer/shared/flag/ComposeBouncerFlags.kt
new file mode 100644
index 0000000..e789475
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/shared/flag/ComposeBouncerFlags.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.bouncer.shared.flag
+
+import com.android.systemui.Flags
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
+import dagger.Module
+import dagger.Provides
+
+interface ComposeBouncerFlags {
+
+    /**
+     * Returns `true` if the Compose bouncer is enabled or if the scene container framework is
+     * enabled; `false` otherwise.
+     */
+    fun isComposeBouncerOrSceneContainerEnabled(): Boolean
+
+    /**
+     * Returns `true` if only compose bouncer is enabled and scene container framework is not
+     * enabled.
+     */
+    @Deprecated(
+        "Avoid using this, this is meant to be used only by the glue code " +
+            "that includes compose bouncer in legacy keyguard.",
+        replaceWith = ReplaceWith("isComposeBouncerOrSceneContainerEnabled()")
+    )
+    fun isOnlyComposeBouncerEnabled(): Boolean
+}
+
+class ComposeBouncerFlagsImpl(private val sceneContainerFlags: SceneContainerFlags) :
+    ComposeBouncerFlags {
+
+    override fun isComposeBouncerOrSceneContainerEnabled(): Boolean {
+        return sceneContainerFlags.isEnabled() || Flags.composeBouncer()
+    }
+
+    @Deprecated(
+        "Avoid using this, this is meant to be used only by the glue code " +
+            "that includes compose bouncer in legacy keyguard.",
+        replaceWith = ReplaceWith("isComposeBouncerOrSceneContainerEnabled()")
+    )
+    override fun isOnlyComposeBouncerEnabled(): Boolean {
+        return !sceneContainerFlags.isEnabled() && Flags.composeBouncer()
+    }
+}
+
+@Module
+object ComposeBouncerFlagsModule {
+    @Provides
+    @SysUISingleton
+    fun impl(sceneContainerFlags: SceneContainerFlags): ComposeBouncerFlags {
+        return ComposeBouncerFlagsImpl(sceneContainerFlags)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt
index dd253a8..f1a0e5e 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt
@@ -4,14 +4,13 @@
 import com.android.keyguard.KeyguardMessageAreaController
 import com.android.keyguard.ViewMediatorCallback
 import com.android.keyguard.dagger.KeyguardBouncerComponent
-import com.android.systemui.Flags
 import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags
 import com.android.systemui.bouncer.ui.BouncerDialogFactory
 import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
 import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel
-import com.android.systemui.compose.ComposeFacade
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.flags.Flags.COMPOSE_BOUNCER_ENABLED
 import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
@@ -55,13 +54,12 @@
 class BouncerViewBinder
 @Inject
 constructor(
+    private val composeBouncerFlags: ComposeBouncerFlags,
     private val legacyBouncerDependencies: Lazy<LegacyBouncerDependencies>,
     private val composeBouncerDependencies: Lazy<ComposeBouncerDependencies>,
 ) {
     fun bind(view: ViewGroup) {
-        if (
-            ComposeFacade.isComposeAvailable() && Flags.composeBouncer() && COMPOSE_BOUNCER_ENABLED
-        ) {
+        if (COMPOSE_BOUNCER_ENABLED && composeBouncerFlags.isOnlyComposeBouncerEnabled()) {
             val deps = composeBouncerDependencies.get()
             ComposeBouncerViewBinder.bind(
                 view,
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/ComposeBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/ComposeBouncerViewBinder.kt
index 7b05395..179fa87 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/ComposeBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/ComposeBouncerViewBinder.kt
@@ -1,15 +1,17 @@
 package com.android.systemui.bouncer.ui.binder
 
 import android.view.ViewGroup
+import androidx.compose.ui.platform.ComposeView
 import androidx.core.view.isVisible
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
+import com.android.compose.theme.PlatformTheme
 import com.android.keyguard.ViewMediatorCallback
 import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.bouncer.ui.BouncerDialogFactory
+import com.android.systemui.bouncer.ui.composable.BouncerContent
 import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
-import com.android.systemui.compose.ComposeFacade
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import kotlinx.coroutines.flow.collectLatest
@@ -27,12 +29,11 @@
         viewMediatorCallback: ViewMediatorCallback?,
     ) {
         view.addView(
-            ComposeFacade.createBouncer(
-                view.context,
-                viewModel,
-                dialogFactory,
-            )
+            ComposeView(view.context).apply {
+                setContent { PlatformTheme { BouncerContent(viewModel, dialogFactory) } }
+            }
         )
+
         view.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.CREATED) {
                 launch {
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 4466cbb..6287578 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
@@ -28,6 +28,7 @@
 import com.android.systemui.bouncer.domain.interactor.BouncerActionButtonInteractor
 import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.SimBouncerInteractor
+import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags
 import com.android.systemui.bouncer.shared.model.BouncerActionButtonModel
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.common.shared.model.Text
@@ -35,7 +36,6 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.inputmethod.domain.interactor.InputMethodInteractor
-import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import com.android.systemui.user.ui.viewmodel.UserActionViewModel
 import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
@@ -72,7 +72,7 @@
     private val simBouncerInteractor: SimBouncerInteractor,
     private val authenticationInteractor: AuthenticationInteractor,
     private val selectedUserInteractor: SelectedUserInteractor,
-    flags: SceneContainerFlags,
+    flags: ComposeBouncerFlags,
     selectedUser: Flow<UserViewModel>,
     users: Flow<List<UserViewModel>>,
     userSwitcherMenu: Flow<List<UserActionViewModel>>,
@@ -233,7 +233,7 @@
     private var lockoutCountdownJob: Job? = null
 
     init {
-        if (flags.isEnabled()) {
+        if (flags.isComposeBouncerOrSceneContainerEnabled()) {
             // Keeps the lockout dialog up-to-date.
             applicationScope.launch {
                 bouncerInteractor.onLockoutStarted.collect {
@@ -478,7 +478,7 @@
         actionButtonInteractor: BouncerActionButtonInteractor,
         authenticationInteractor: AuthenticationInteractor,
         selectedUserInteractor: SelectedUserInteractor,
-        flags: SceneContainerFlags,
+        flags: ComposeBouncerFlags,
         userSwitcherViewModel: UserSwitcherViewModel,
         clock: SystemClock,
         devicePolicyManager: DevicePolicyManager,
diff --git a/packages/SystemUI/src/com/android/systemui/camera/CameraRotationModule.kt b/packages/SystemUI/src/com/android/systemui/camera/CameraRotationModule.kt
new file mode 100644
index 0000000..f123828
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/camera/CameraRotationModule.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.camera
+
+import com.android.systemui.camera.data.repository.CameraAutoRotateRepository
+import com.android.systemui.camera.data.repository.CameraAutoRotateRepositoryImpl
+import com.android.systemui.camera.data.repository.CameraSensorPrivacyRepository
+import com.android.systemui.camera.data.repository.CameraSensorPrivacyRepositoryImpl
+import dagger.Binds
+import dagger.Module
+
+/** Module for repositories that provide data regarding camera rotation state. */
+@Module
+interface CameraRotationModule {
+
+    @Binds
+    fun bindsPrivacyRepoImpl(impl: CameraSensorPrivacyRepositoryImpl): CameraSensorPrivacyRepository
+    @Binds fun bindsRotateRepoImpl(impl: CameraAutoRotateRepositoryImpl): CameraAutoRotateRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/camera/data/repository/CameraAutoRotateRepository.kt b/packages/SystemUI/src/com/android/systemui/camera/data/repository/CameraAutoRotateRepository.kt
new file mode 100644
index 0000000..023fd28
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/camera/data/repository/CameraAutoRotateRepository.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.camera.data.repository
+
+import android.os.UserHandle
+import android.provider.Settings
+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.settings.SecureSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
+
+interface CameraAutoRotateRepository {
+    /** @return true if camera auto rotate setting is enabled */
+    fun isCameraAutoRotateSettingEnabled(userHandle: UserHandle): StateFlow<Boolean>
+}
+
+@SysUISingleton
+class CameraAutoRotateRepositoryImpl
+@Inject
+constructor(
+    private val secureSettings: SecureSettings,
+    @Background private val bgCoroutineContext: CoroutineContext,
+    @Application private val applicationScope: CoroutineScope,
+) : CameraAutoRotateRepository {
+    private val userMap = mutableMapOf<Int, StateFlow<Boolean>>()
+
+    override fun isCameraAutoRotateSettingEnabled(userHandle: UserHandle): StateFlow<Boolean> {
+        return userMap.getOrPut(userHandle.identifier) {
+            secureSettings
+                .observerFlow(userHandle.identifier, Settings.Secure.CAMERA_AUTOROTATE)
+                .map { isAutoRotateSettingEnabled(userHandle.identifier) }
+                .onStart { emit(isAutoRotateSettingEnabled(userHandle.identifier)) }
+                .flowOn(bgCoroutineContext)
+                .stateIn(applicationScope, SharingStarted.WhileSubscribed(), false)
+        }
+    }
+
+    private fun isAutoRotateSettingEnabled(userId: Int) =
+        secureSettings.getIntForUser(SETTING_NAME, DISABLED, userId) == ENABLED
+
+    private companion object {
+        const val SETTING_NAME = Settings.Secure.CAMERA_AUTOROTATE
+        const val DISABLED = 0
+        const val ENABLED = 1
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/camera/data/repository/CameraSensorPrivacyRepository.kt b/packages/SystemUI/src/com/android/systemui/camera/data/repository/CameraSensorPrivacyRepository.kt
new file mode 100644
index 0000000..7816a14
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/camera/data/repository/CameraSensorPrivacyRepository.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.camera.data.repository
+
+import android.hardware.SensorPrivacyManager
+import android.hardware.SensorPrivacyManager.Sensors.CAMERA
+import android.os.UserHandle
+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 javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
+
+interface CameraSensorPrivacyRepository {
+    /** Tracks whether camera sensor privacy is enabled. */
+    fun isEnabled(userHandle: UserHandle): StateFlow<Boolean>
+}
+
+@SysUISingleton
+class CameraSensorPrivacyRepositoryImpl
+@Inject
+constructor(
+    @Background private val bgCoroutineContext: CoroutineContext,
+    @Application private val scope: CoroutineScope,
+    private val privacyManager: SensorPrivacyManager,
+) : CameraSensorPrivacyRepository {
+    private val userMap = mutableMapOf<Int, StateFlow<Boolean>>()
+
+    /** Whether camera sensor privacy is enabled */
+    override fun isEnabled(userHandle: UserHandle): StateFlow<Boolean> =
+        userMap.getOrPut(userHandle.identifier) {
+            privacyManager
+                .isEnabled(userHandle)
+                .flowOn(bgCoroutineContext)
+                .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+        }
+}
+
+fun SensorPrivacyManager.isEnabled(userHandle: UserHandle): Flow<Boolean> {
+    return conflatedCallbackFlow {
+            val privacyCallback =
+                SensorPrivacyManager.OnSensorPrivacyChangedListener { sensor, enabled ->
+                    if (sensor == CAMERA) {
+                        trySend(enabled)
+                    }
+                }
+            addSensorPrivacyListener(CAMERA, userHandle.identifier, privacyCallback)
+            awaitClose { removeSensorPrivacyListener(privacyCallback) }
+        }
+        .onStart { emit(isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE, CAMERA)) }
+        .distinctUntilChanged()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index f7ba5a4..c3c7411 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -16,25 +16,23 @@
 
 package com.android.systemui.communal
 
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.CoreStartable
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
-import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dock.DockManager
-import com.android.systemui.dock.retrieveIsDocked
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionStep
-import com.android.systemui.util.kotlin.sample
 import javax.inject.Inject
 import kotlin.time.Duration.Companion.seconds
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.FlowPreview
 import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.debounce
 import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.mapLatest
@@ -65,39 +63,40 @@
             .onEach { nextScene -> communalInteractor.onSceneChanged(nextScene) }
             .launchIn(applicationScope)
 
+        // TODO(b/322787129): re-enable once custom animations are in place
         // Handle automatically switching to communal when docked.
-        dockManager
-            .retrieveIsDocked()
-            // Allow some time after docking to ensure the dream doesn't start. If the dream
-            // starts, then we don't want to automatically transition to glanceable hub.
-            .debounce(DOCK_DEBOUNCE_DELAY)
-            .sample(keyguardTransitionInteractor.startedKeyguardState, ::Pair)
-            .onEach { (docked, lastStartedState) ->
-                if (docked && lastStartedState == KeyguardState.LOCKSCREEN) {
-                    communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
-                }
-            }
-            .launchIn(bgScope)
+        //        dockManager
+        //            .retrieveIsDocked()
+        //            // Allow some time after docking to ensure the dream doesn't start. If the
+        // dream
+        //            // starts, then we don't want to automatically transition to glanceable hub.
+        //            .debounce(DOCK_DEBOUNCE_DELAY)
+        //            .sample(keyguardTransitionInteractor.startedKeyguardState, ::Pair)
+        //            .onEach { (docked, lastStartedState) ->
+        //                if (docked && lastStartedState == KeyguardState.LOCKSCREEN) {
+        //                    communalInteractor.onSceneChanged(CommunalScenes.Communal)
+        //                }
+        //            }
+        //            .launchIn(bgScope)
     }
 
     private suspend fun determineSceneAfterTransition(
         lastStartedTransition: TransitionStep,
-    ): CommunalSceneKey? {
+    ): SceneKey? {
         val to = lastStartedTransition.to
         val from = lastStartedTransition.from
         val docked = dockManager.isDocked
 
         return when {
-            to == KeyguardState.DREAMING -> CommunalSceneKey.Blank
-            docked && to == KeyguardState.LOCKSCREEN && from != KeyguardState.GLANCEABLE_HUB -> {
-                CommunalSceneKey.Communal
+            docked && to == KeyguardState.LOCKSCREEN && from == KeyguardState.DREAMING -> {
+                CommunalScenes.Communal
             }
-            to == KeyguardState.GONE -> CommunalSceneKey.Blank
+            to == KeyguardState.GONE -> CommunalScenes.Blank
             !docked && !KeyguardState.deviceIsAwakeInState(to) -> {
                 // If the user taps the screen and wakes the device within this timeout, we don't
                 // want to dismiss the hub
                 delay(AWAKE_DEBOUNCE_DELAY)
-                CommunalSceneKey.Blank
+                CommunalScenes.Blank
             }
             else -> null
         }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
index f4a3bcb..201ce83 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalRepository.kt
@@ -16,8 +16,9 @@
 
 package com.android.systemui.communal.data.repository
 
-import com.android.systemui.communal.shared.model.CommunalSceneKey
-import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
+import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.scene.data.repository.SceneContainerRepository
@@ -40,20 +41,20 @@
      * Target scene as requested by the underlying [SceneTransitionLayout] or through
      * [setDesiredScene].
      */
-    val desiredScene: StateFlow<CommunalSceneKey>
+    val desiredScene: StateFlow<SceneKey>
 
     /** Exposes the transition state of the communal [SceneTransitionLayout]. */
-    val transitionState: StateFlow<ObservableCommunalTransitionState>
+    val transitionState: StateFlow<ObservableTransitionState>
 
     /** Updates the requested scene. */
-    fun setDesiredScene(desiredScene: CommunalSceneKey)
+    fun setDesiredScene(desiredScene: SceneKey)
 
     /**
      * Updates the transition state of the hub [SceneTransitionLayout].
      *
      * Note that you must call is with `null` when the UI is done or risk a memory leak.
      */
-    fun setTransitionState(transitionState: Flow<ObservableCommunalTransitionState>?)
+    fun setTransitionState(transitionState: Flow<ObservableTransitionState>?)
 }
 
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -66,14 +67,12 @@
     sceneContainerRepository: SceneContainerRepository,
 ) : CommunalRepository {
 
-    private val _desiredScene: MutableStateFlow<CommunalSceneKey> =
-        MutableStateFlow(CommunalSceneKey.DEFAULT)
-    override val desiredScene: StateFlow<CommunalSceneKey> = _desiredScene.asStateFlow()
+    private val _desiredScene: MutableStateFlow<SceneKey> = MutableStateFlow(CommunalScenes.Default)
+    override val desiredScene: StateFlow<SceneKey> = _desiredScene.asStateFlow()
 
-    private val defaultTransitionState =
-        ObservableCommunalTransitionState.Idle(CommunalSceneKey.DEFAULT)
-    private val _transitionState = MutableStateFlow<Flow<ObservableCommunalTransitionState>?>(null)
-    override val transitionState: StateFlow<ObservableCommunalTransitionState> =
+    private val defaultTransitionState = ObservableTransitionState.Idle(CommunalScenes.Default)
+    private val _transitionState = MutableStateFlow<Flow<ObservableTransitionState>?>(null)
+    override val transitionState: StateFlow<ObservableTransitionState> =
         _transitionState
             .flatMapLatest { innerFlowOrNull -> innerFlowOrNull ?: flowOf(defaultTransitionState) }
             .stateIn(
@@ -82,7 +81,7 @@
                 initialValue = defaultTransitionState,
             )
 
-    override fun setDesiredScene(desiredScene: CommunalSceneKey) {
+    override fun setDesiredScene(desiredScene: SceneKey) {
         _desiredScene.value = desiredScene
     }
 
@@ -91,7 +90,7 @@
      *
      * Note that you must call is with `null` when the UI is done or risk a memory leak.
      */
-    override fun setTransitionState(transitionState: Flow<ObservableCommunalTransitionState>?) {
+    override fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) {
         _transitionState.value = transitionState
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 5d52541..8142957 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -19,18 +19,20 @@
 import android.app.smartspace.SmartspaceTarget
 import android.content.ComponentName
 import android.os.UserHandle
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.communal.data.repository.CommunalMediaRepository
 import com.android.systemui.communal.data.repository.CommunalPrefsRepository
 import com.android.systemui.communal.data.repository.CommunalRepository
 import com.android.systemui.communal.data.repository.CommunalWidgetRepository
 import com.android.systemui.communal.domain.model.CommunalContentModel
+import com.android.systemui.communal.domain.model.CommunalContentModel.WidgetContent
 import com.android.systemui.communal.shared.model.CommunalContentSize
 import com.android.systemui.communal.shared.model.CommunalContentSize.FULL
 import com.android.systemui.communal.shared.model.CommunalContentSize.HALF
 import com.android.systemui.communal.shared.model.CommunalContentSize.THIRD
-import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
-import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
 import com.android.systemui.communal.widgets.CommunalAppWidgetHost
 import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
 import com.android.systemui.communal.widgets.WidgetConfigurator
@@ -45,7 +47,7 @@
 import com.android.systemui.log.table.logDiffsForTable
 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.Scenes
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.smartspace.data.repository.SmartspaceRepository
 import com.android.systemui.util.kotlin.BooleanFlowOperators.and
@@ -130,34 +132,33 @@
      * Target scene as requested by the underlying [SceneTransitionLayout] or through
      * [onSceneChanged].
      *
-     * If [isCommunalAvailable] is false, will return [CommunalSceneKey.Blank]
+     * If [isCommunalAvailable] is false, will return [CommunalScenes.Blank]
      */
-    val desiredScene: Flow<CommunalSceneKey> =
+    val desiredScene: Flow<SceneKey> =
         communalRepository.desiredScene.combine(isCommunalAvailable) { scene, available ->
-            if (available) scene else CommunalSceneKey.Blank
+            if (available) scene else CommunalScenes.Blank
         }
 
     /** Transition state of the hub mode. */
-    val transitionState: StateFlow<ObservableCommunalTransitionState> =
-        communalRepository.transitionState
+    val transitionState: StateFlow<ObservableTransitionState> = communalRepository.transitionState
 
     /**
      * Updates the transition state of the hub [SceneTransitionLayout].
      *
      * Note that you must call is with `null` when the UI is done or risk a memory leak.
      */
-    fun setTransitionState(transitionState: Flow<ObservableCommunalTransitionState>?) {
+    fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) {
         communalRepository.setTransitionState(transitionState)
     }
 
     /** Returns a flow that tracks the progress of transitions to the given scene from 0-1. */
-    fun transitionProgressToScene(targetScene: CommunalSceneKey) =
+    fun transitionProgressToScene(targetScene: SceneKey) =
         transitionState
             .flatMapLatest { state ->
                 when (state) {
-                    is ObservableCommunalTransitionState.Idle ->
+                    is ObservableTransitionState.Idle ->
                         flowOf(CommunalTransitionProgress.Idle(state.scene))
-                    is ObservableCommunalTransitionState.Transition ->
+                    is ObservableTransitionState.Transition ->
                         if (state.toScene == targetScene) {
                             state.progress.map {
                                 CommunalTransitionProgress.Transition(
@@ -175,7 +176,7 @@
 
     /**
      * Flow that emits a boolean if the communal UI is the target scene, ie. the [desiredScene] is
-     * the [CommunalSceneKey.Communal].
+     * the [CommunalScenes.Communal].
      *
      * This will be true as soon as the desired scene is set programmatically or at whatever point
      * during a fling that SceneTransitionLayout determines that the end state will be the communal
@@ -190,9 +191,9 @@
         flow { emit(sceneContainerFlags.isEnabled()) }
             .flatMapLatest { sceneContainerEnabled ->
                 if (sceneContainerEnabled) {
-                    sceneInteractor.currentScene.map { it == SceneKey.Communal }
+                    sceneInteractor.currentScene.map { it == Scenes.Communal }
                 } else {
-                    desiredScene.map { it == CommunalSceneKey.Communal }
+                    desiredScene.map { it == CommunalScenes.Communal }
                 }
             }
             .distinctUntilChanged()
@@ -219,7 +220,7 @@
      */
     val isIdleOnCommunal: Flow<Boolean> =
         communalRepository.transitionState.map {
-            it is ObservableCommunalTransitionState.Idle && it.scene == CommunalSceneKey.Communal
+            it is ObservableTransitionState.Idle && it.scene == CommunalScenes.Communal
         }
 
     /**
@@ -229,11 +230,11 @@
      */
     val isCommunalVisible: Flow<Boolean> =
         communalRepository.transitionState.map {
-            !(it is ObservableCommunalTransitionState.Idle && it.scene == CommunalSceneKey.Blank)
+            !(it is ObservableTransitionState.Idle && it.scene == CommunalScenes.Blank)
         }
 
     /** Callback received whenever the [SceneTransitionLayout] finishes a scene transition. */
-    fun onSceneChanged(newScene: CommunalSceneKey) {
+    fun onSceneChanged(newScene: SceneKey) {
         communalRepository.setDesiredScene(newScene)
     }
 
@@ -278,14 +279,25 @@
         }
 
     /** A list of widget content to be displayed in the communal hub. */
-    val widgetContent: Flow<List<CommunalContentModel.Widget>> =
-        widgetRepository.communalWidgets.map { widgets ->
-            filterWidgetsByExistingUsers(widgets).map Widget@{ widget ->
-                return@Widget CommunalContentModel.Widget(
-                    appWidgetId = widget.appWidgetId,
-                    providerInfo = widget.providerInfo,
-                    appWidgetHost = appWidgetHost,
-                )
+    val widgetContent: Flow<List<WidgetContent>> =
+        combine(
+            widgetRepository.communalWidgets.map { filterWidgetsByExistingUsers(it) },
+            communalSettingsInteractor.communalWidgetCategories
+        ) { widgets, allowedCategories ->
+            widgets.map { widget ->
+                if (widget.providerInfo.widgetCategory and allowedCategories != 0) {
+                    // At least one category this widget specified is allowed, so show it
+                    WidgetContent.Widget(
+                        appWidgetId = widget.appWidgetId,
+                        providerInfo = widget.providerInfo,
+                        appWidgetHost = appWidgetHost,
+                    )
+                } else {
+                    WidgetContent.DisabledWidget(
+                        appWidgetId = widget.appWidgetId,
+                        providerInfo = widget.providerInfo,
+                    )
+                }
             }
         }
 
@@ -410,7 +422,7 @@
 /** Simplified transition progress data class for tracking a single transition between scenes. */
 sealed class CommunalTransitionProgress {
     /** No transition/animation is currently running. */
-    data class Idle(val scene: CommunalSceneKey) : CommunalTransitionProgress()
+    data class Idle(val scene: SceneKey) : CommunalTransitionProgress()
 
     /** There is a transition animating to the expected scene. */
     data class Transition(
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
index ae019a1..c64f666 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
@@ -18,6 +18,7 @@
 
 import android.appwidget.AppWidgetProviderInfo
 import android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE
+import android.content.pm.ApplicationInfo
 import android.widget.RemoteViews
 import com.android.systemui.communal.shared.model.CommunalContentSize
 import com.android.systemui.communal.widgets.CommunalAppWidgetHost
@@ -42,20 +43,37 @@
         val createdTimestampMillis: Long
     }
 
-    data class Widget(
-        val appWidgetId: Int,
-        val providerInfo: AppWidgetProviderInfo,
-        val appWidgetHost: CommunalAppWidgetHost,
-    ) : CommunalContentModel {
-        override val key = KEY.widget(appWidgetId)
-        // Widget size is always half.
-        override val size = CommunalContentSize.HALF
+    sealed interface WidgetContent : CommunalContentModel {
+        val appWidgetId: Int
+        val providerInfo: AppWidgetProviderInfo
 
-        /** Whether this widget can be reconfigured after it has already been added. */
-        val reconfigurable: Boolean
-            get() =
-                (providerInfo.widgetFeatures and WIDGET_FEATURE_RECONFIGURABLE != 0) &&
-                    providerInfo.configure != null
+        data class Widget(
+            override val appWidgetId: Int,
+            override val providerInfo: AppWidgetProviderInfo,
+            val appWidgetHost: CommunalAppWidgetHost,
+        ) : WidgetContent {
+            override val key = KEY.widget(appWidgetId)
+            // Widget size is always half.
+            override val size = CommunalContentSize.HALF
+
+            /** Whether this widget can be reconfigured after it has already been added. */
+            val reconfigurable: Boolean
+                get() =
+                    (providerInfo.widgetFeatures and WIDGET_FEATURE_RECONFIGURABLE != 0) &&
+                        providerInfo.configure != null
+        }
+
+        data class DisabledWidget(
+            override val appWidgetId: Int,
+            override val providerInfo: AppWidgetProviderInfo
+        ) : WidgetContent {
+            override val key = KEY.disabledWidget(appWidgetId)
+            // Widget size is always half.
+            override val size = CommunalContentSize.HALF
+
+            val appInfo: ApplicationInfo?
+                get() = providerInfo.providerInfo?.applicationInfo
+        }
     }
 
     /** A placeholder item representing a new widget being added */
@@ -111,6 +129,10 @@
                 return "widget_$id"
             }
 
+            fun disabledWidget(id: Int): String {
+                return "disabled_widget_$id"
+            }
+
             fun widgetPlaceholder(): String {
                 return "widget_placeholder_${UUID.randomUUID()}"
             }
@@ -129,5 +151,5 @@
         }
     }
 
-    fun isWidget() = this is Widget
+    fun isWidgetContent() = this is WidgetContent
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/log/CommunalLoggerStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/log/CommunalLoggerStartable.kt
index 889023e..f2b4738 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/log/CommunalLoggerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/log/CommunalLoggerStartable.kt
@@ -16,12 +16,12 @@
 
 package com.android.systemui.communal.log
 
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.CoreStartable
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.shared.log.CommunalUiEvent
-import com.android.systemui.communal.shared.model.CommunalSceneKey
-import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
+import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.util.kotlin.pairwise
@@ -87,25 +87,25 @@
 }
 
 /** Whether currently in communal scene. */
-private fun ObservableCommunalTransitionState.isOnCommunal(): Boolean {
-    return this is ObservableCommunalTransitionState.Idle && scene == CommunalSceneKey.Communal
+private fun ObservableTransitionState.isOnCommunal(): Boolean {
+    return this is ObservableTransitionState.Idle && scene == CommunalScenes.Communal
 }
 
 /** Whether currently in a scene other than communal. */
-private fun ObservableCommunalTransitionState.isNotOnCommunal(): Boolean {
-    return this is ObservableCommunalTransitionState.Idle && scene != CommunalSceneKey.Communal
+private fun ObservableTransitionState.isNotOnCommunal(): Boolean {
+    return this is ObservableTransitionState.Idle && scene != CommunalScenes.Communal
 }
 
 /** Whether currently transitioning from another scene to communal. */
-private fun ObservableCommunalTransitionState.isSwipingToCommunal(): Boolean {
-    return this is ObservableCommunalTransitionState.Transition &&
-        toScene == CommunalSceneKey.Communal &&
+private fun ObservableTransitionState.isSwipingToCommunal(): Boolean {
+    return this is ObservableTransitionState.Transition &&
+        toScene == CommunalScenes.Communal &&
         isInitiatedByUserInput
 }
 
 /** Whether currently transitioning from communal to another scene. */
-private fun ObservableCommunalTransitionState.isSwipingFromCommunal(): Boolean {
-    return this is ObservableCommunalTransitionState.Transition &&
-        fromScene == CommunalSceneKey.Communal &&
+private fun ObservableTransitionState.isSwipingFromCommunal(): Boolean {
+    return this is ObservableTransitionState.Transition &&
+        fromScene == CommunalScenes.Communal &&
         isInitiatedByUserInput
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalSceneKey.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalScenes.kt
similarity index 74%
rename from packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalSceneKey.kt
rename to packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalScenes.kt
index c68dd4f..d5a56c1 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalSceneKey.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalScenes.kt
@@ -16,21 +16,15 @@
 
 package com.android.systemui.communal.shared.model
 
+import com.android.compose.animation.scene.SceneKey
+
 /** Definition of the possible scenes for the communal UI. */
-sealed class CommunalSceneKey(
-    private val loggingName: String,
-) {
-    /** The communal scene containing the hub UI. */
-    object Communal : CommunalSceneKey("communal")
-
+object CommunalScenes {
     /** The default scene, shows nothing and is only there to allow swiping to communal. */
-    object Blank : CommunalSceneKey("blank")
+    @JvmField val Blank = SceneKey("blank")
 
-    override fun toString(): String {
-        return loggingName
-    }
+    /** The communal scene containing the hub UI. */
+    @JvmField val Communal = SceneKey("communal")
 
-    companion object {
-        val DEFAULT = Blank
-    }
+    @JvmField val Default = Blank
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/ObservableCommunalTransitionState.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/ObservableCommunalTransitionState.kt
deleted file mode 100644
index d834715..0000000
--- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/ObservableCommunalTransitionState.kt
+++ /dev/null
@@ -1,54 +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.communal.shared.model
-
-import kotlinx.coroutines.flow.Flow
-
-/**
- * This is a fork of the `com.android.compose.animation.scene.ObservableTransitionState` class.
- *
- * TODO(b/315490861): remove this fork, once we can compile Compose into System UI.
- */
-sealed class ObservableCommunalTransitionState {
-    /** No transition/animation is currently running. */
-    data class Idle(val scene: CommunalSceneKey) : ObservableCommunalTransitionState()
-
-    /** There is a transition animating between two scenes. */
-    data class Transition(
-        val fromScene: CommunalSceneKey,
-        val toScene: CommunalSceneKey,
-        val progress: Flow<Float>,
-
-        /**
-         * Whether the transition was originally triggered by user input rather than being
-         * programmatic. If this value is initially true, it will remain true until the transition
-         * fully completes, even if the user input that triggered the transition has ended. Any
-         * sub-transitions launched by this one will inherit this value. For example, if the user
-         * drags a pointer but does not exceed the threshold required to transition to another
-         * scene, this value will remain true after the pointer is no longer touching the screen and
-         * will be true in any transition created to animate back to the original position.
-         */
-        val isInitiatedByUserInput: Boolean,
-
-        /**
-         * Whether user input is currently driving the transition. For example, if a user is
-         * dragging a pointer, this emits true. Once they lift their finger, this emits false while
-         * the transition completes/settles.
-         */
-        val isUserInputOngoing: Flow<Boolean>,
-    ) : ObservableCommunalTransitionState()
-}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
index 3ec9a26..35372cd 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
@@ -18,10 +18,10 @@
 
 import android.content.ComponentName
 import android.os.UserHandle
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.domain.model.CommunalContentModel
-import com.android.systemui.communal.shared.model.CommunalSceneKey
-import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
 import com.android.systemui.communal.widgets.WidgetConfigurator
 import com.android.systemui.media.controls.ui.view.MediaHost
 import kotlinx.coroutines.flow.Flow
@@ -34,7 +34,7 @@
     private val communalInteractor: CommunalInteractor,
     val mediaHost: MediaHost,
 ) {
-    val currentScene: Flow<CommunalSceneKey> = communalInteractor.desiredScene
+    val currentScene: Flow<SceneKey> = communalInteractor.desiredScene
 
     /** Whether widgets are currently being re-ordered. */
     open val reorderingWidgets: StateFlow<Boolean> = MutableStateFlow(false)
@@ -45,7 +45,7 @@
     val selectedKey: StateFlow<String?>
         get() = _selectedKey
 
-    fun onSceneChanged(scene: CommunalSceneKey) {
+    fun onSceneChanged(scene: SceneKey) {
         communalInteractor.onSceneChanged(scene)
     }
 
@@ -54,7 +54,7 @@
      *
      * Note that you must call is with `null` when the UI is done or risk a memory leak.
      */
-    fun setTransitionState(transitionState: Flow<ObservableCommunalTransitionState>?) {
+    fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) {
         communalInteractor.setTransitionState(transitionState)
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index fc9a7df..35b27aa 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -21,6 +21,7 @@
 import com.android.systemui.communal.domain.model.CommunalContentModel
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.Logger
 import com.android.systemui.log.dagger.CommunalLog
@@ -46,6 +47,7 @@
 import kotlinx.coroutines.launch
 
 /** The default view model used for showing the communal hub. */
+@OptIn(ExperimentalCoroutinesApi::class)
 @SysUISingleton
 class CommunalViewModel
 @Inject
@@ -54,6 +56,7 @@
     private val communalInteractor: CommunalInteractor,
     tutorialInteractor: CommunalTutorialInteractor,
     shadeInteractor: ShadeInteractor,
+    deviceEntryInteractor: DeviceEntryInteractor,
     @Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost,
     @CommunalLog logBuffer: LogBuffer,
 ) : BaseCommunalViewModel(communalInteractor, mediaHost) {
@@ -87,6 +90,8 @@
     /** Whether touches should be disabled in communal */
     val touchesAllowed: Flow<Boolean> = not(shadeInteractor.isAnyFullyExpanded)
 
+    val deviceUnlocked: Flow<Boolean> = deviceEntryInteractor.isUnlocked
+
     init {
         // Initialize our media host for the UMO. This only needs to happen once and must be done
         // before the MediaHierarchyManager attempts to move the UMO to the hub.
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt
index 080dbed..93e2b37 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt
@@ -21,6 +21,7 @@
 import android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_CONFIGURATION_OPTIONAL
 import android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE
 import android.content.ComponentName
+import android.os.Bundle
 import android.os.UserHandle
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.Logger
@@ -56,6 +57,7 @@
             return widgetInfo.configure != null && !configurationOptional
         }
     }
+
     private val logger = Logger(logBuffer, TAG)
 
     /**
@@ -84,9 +86,16 @@
 
     private fun bindWidget(widgetId: Int, user: UserHandle, provider: ComponentName): Boolean {
         if (appWidgetManager.isPresent) {
+            val options =
+                Bundle().apply {
+                    putInt(
+                        AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
+                        AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD,
+                    )
+                }
             return appWidgetManager
                 .get()
-                .bindAppWidgetIdIfAllowed(widgetId, user, provider, /* options */ null)
+                .bindAppWidgetIdIfAllowed(widgetId, user, provider, options)
         }
         return false
     }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
index a5a390d..b6ad26b 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
@@ -25,14 +25,21 @@
 import android.view.IWindowManager
 import android.view.WindowInsets
 import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
 import androidx.activity.result.ActivityResultLauncher
 import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.ui.Modifier
+import com.android.compose.theme.LocalAndroidColorScheme
+import com.android.compose.theme.PlatformTheme
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.communal.shared.log.CommunalUiEvent
-import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.communal.shared.model.CommunalScenes
+import com.android.systemui.communal.ui.compose.CommunalHub
 import com.android.systemui.communal.ui.viewmodel.CommunalEditModeViewModel
 import com.android.systemui.communal.util.WidgetPickerIntentUtils.getWidgetExtraFromIntent
-import com.android.systemui.compose.ComposeFacade.setCommunalEditWidgetActivityContent
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.Logger
 import com.android.systemui.log.dagger.CommunalLog
@@ -110,56 +117,68 @@
         val preselectedKey = intent.getStringExtra(EXTRA_PRESELECTED_KEY)
         communalViewModel.setSelectedKey(preselectedKey)
 
-        setCommunalEditWidgetActivityContent(
-            activity = this,
-            viewModel = communalViewModel,
-            widgetConfigurator = widgetConfigurator,
-            onOpenWidgetPicker = {
-                val intent =
-                    Intent(Intent.ACTION_MAIN).also { it.addCategory(Intent.CATEGORY_HOME) }
-                packageManager
-                    .resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY)
-                    ?.activityInfo
-                    ?.packageName
-                    ?.let { packageName ->
-                        try {
-                            addWidgetActivityLauncher.launch(
-                                Intent(Intent.ACTION_PICK).apply {
-                                    setPackage(packageName)
-                                    putExtra(
-                                        EXTRA_DESIRED_WIDGET_WIDTH,
-                                        resources.getDimensionPixelSize(
-                                            R.dimen.communal_widget_picker_desired_width
-                                        )
-                                    )
-                                    putExtra(
-                                        EXTRA_DESIRED_WIDGET_HEIGHT,
-                                        resources.getDimensionPixelSize(
-                                            R.dimen.communal_widget_picker_desired_height
-                                        )
-                                    )
-                                    putExtra(
-                                        AppWidgetManager.EXTRA_CATEGORY_FILTER,
-                                        communalViewModel.getCommunalWidgetCategories
-                                    )
-                                }
-                            )
-                        } catch (e: Exception) {
-                            Log.e(TAG, "Failed to launch widget picker activity", e)
-                        }
-                    }
-                    ?: run { Log.e(TAG, "Couldn't resolve launcher package name") }
-            },
-            onEditDone = {
-                try {
-                    communalViewModel.onSceneChanged(CommunalSceneKey.Communal)
-                    checkNotNull(windowManagerService).lockNow(/* options */ null)
-                    finish()
-                } catch (e: RemoteException) {
-                    Log.e(TAG, "Couldn't lock the device as WindowManager is dead.")
+        setContent {
+            PlatformTheme {
+                Box(
+                    modifier =
+                        Modifier.fillMaxSize()
+                            .background(LocalAndroidColorScheme.current.outlineVariant),
+                ) {
+                    CommunalHub(
+                        viewModel = communalViewModel,
+                        onOpenWidgetPicker = ::onOpenWidgetPicker,
+                        widgetConfigurator = widgetConfigurator,
+                        onEditDone = ::onEditDone,
+                    )
                 }
             }
-        )
+        }
+    }
+
+    private fun onOpenWidgetPicker() {
+        val intent = Intent(Intent.ACTION_MAIN).also { it.addCategory(Intent.CATEGORY_HOME) }
+        packageManager
+            .resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY)
+            ?.activityInfo
+            ?.packageName
+            ?.let { packageName ->
+                try {
+                    addWidgetActivityLauncher.launch(
+                        Intent(Intent.ACTION_PICK).apply {
+                            setPackage(packageName)
+                            putExtra(
+                                EXTRA_DESIRED_WIDGET_WIDTH,
+                                resources.getDimensionPixelSize(
+                                    R.dimen.communal_widget_picker_desired_width
+                                )
+                            )
+                            putExtra(
+                                EXTRA_DESIRED_WIDGET_HEIGHT,
+                                resources.getDimensionPixelSize(
+                                    R.dimen.communal_widget_picker_desired_height
+                                )
+                            )
+                            putExtra(
+                                AppWidgetManager.EXTRA_CATEGORY_FILTER,
+                                communalViewModel.getCommunalWidgetCategories
+                            )
+                        }
+                    )
+                } catch (e: Exception) {
+                    Log.e(TAG, "Failed to launch widget picker activity", e)
+                }
+            }
+            ?: run { Log.e(TAG, "Couldn't resolve launcher package name") }
+    }
+
+    private fun onEditDone() {
+        try {
+            communalViewModel.onSceneChanged(CommunalScenes.Communal)
+            checkNotNull(windowManagerService).lockNow(/* options */ null)
+            finish()
+        } catch (e: RemoteException) {
+            Log.e(TAG, "Couldn't lock the device as WindowManager is dead.")
+        }
     }
 
     override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
diff --git a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
deleted file mode 100644
index a0aaa90..0000000
--- a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.systemui.compose
-
-import android.content.Context
-import android.view.View
-import android.view.WindowInsets
-import androidx.activity.ComponentActivity
-import androidx.lifecycle.LifecycleOwner
-import com.android.systemui.bouncer.ui.BouncerDialogFactory
-import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
-import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
-import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
-import com.android.systemui.communal.widgets.WidgetConfigurator
-import com.android.systemui.keyboard.stickykeys.ui.viewmodel.StickyKeysIndicatorViewModel
-import com.android.systemui.keyguard.shared.model.LockscreenSceneBlueprint
-import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
-import com.android.systemui.people.ui.viewmodel.PeopleViewModel
-import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
-import com.android.systemui.scene.shared.model.Scene
-import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
-import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.StateFlow
-
-/**
- * A facade to interact with Compose, when it is available.
- *
- * You should access this facade by calling the static methods on
- * [com.android.systemui.compose.ComposeFacade] directly.
- */
-interface BaseComposeFacade {
-    /**
-     * Whether Compose is currently available. This function should be checked before calling any
-     * other functions on this facade.
-     *
-     * This value will never change at runtime.
-     */
-    fun isComposeAvailable(): Boolean
-
-    /**
-     * Return the [ComposeInitializer] to make Compose usable in windows outside normal activities.
-     */
-    fun composeInitializer(): ComposeInitializer
-
-    /** Bind the content of [activity] to [viewModel]. */
-    fun setPeopleSpaceActivityContent(
-        activity: ComponentActivity,
-        viewModel: PeopleViewModel,
-        onResult: (PeopleViewModel.Result) -> Unit,
-    )
-
-    /** Bind the content of [activity] to [viewModel]. */
-    fun setCommunalEditWidgetActivityContent(
-        activity: ComponentActivity,
-        viewModel: BaseCommunalViewModel,
-        widgetConfigurator: WidgetConfigurator,
-        onOpenWidgetPicker: () -> Unit,
-        onEditDone: () -> Unit,
-    )
-
-    fun setVolumePanelActivityContent(
-        activity: ComponentActivity,
-        viewModel: VolumePanelViewModel,
-        onDismiss: () -> Unit,
-    )
-
-    /** Create a [View] to represent [viewModel] on screen. */
-    fun createFooterActionsView(
-        context: Context,
-        viewModel: FooterActionsViewModel,
-        qsVisibilityLifecycleOwner: LifecycleOwner,
-    ): View
-
-    /** Create a [View] to represent [viewModel] on screen. */
-    fun createSceneContainerView(
-        scope: CoroutineScope,
-        context: Context,
-        viewModel: SceneContainerViewModel,
-        windowInsets: StateFlow<WindowInsets?>,
-        sceneByKey: Map<SceneKey, Scene>,
-        dataSourceDelegator: SceneDataSourceDelegator,
-    ): View
-
-    /** Creates sticky key indicator content presenting provided [viewModel] */
-    fun createStickyKeysIndicatorContent(
-        context: Context,
-        viewModel: StickyKeysIndicatorViewModel
-    ): View
-
-    /** Create a [View] to represent [viewModel] on screen. */
-    fun createCommunalView(
-        context: Context,
-        viewModel: BaseCommunalViewModel,
-    ): View
-
-    /** Create a [View] to represent the [BouncerViewModel]. */
-    fun createBouncer(
-        context: Context,
-        viewModel: BouncerViewModel,
-        dialogFactory: BouncerDialogFactory,
-    ): View
-
-    /** Creates a container that hosts the communal UI and handles gesture transitions. */
-    fun createCommunalContainer(context: Context, viewModel: CommunalViewModel): View
-
-    /** Creates a [View] that represents the Lockscreen. */
-    fun createLockscreen(
-        context: Context,
-        viewModel: LockscreenContentViewModel,
-        blueprints: Set<@JvmSuppressWildcards LockscreenSceneBlueprint>,
-    ): View
-}
diff --git a/packages/SystemUI/src/com/android/systemui/compose/ComposeInitializer.kt b/packages/SystemUI/src/com/android/systemui/compose/ComposeInitializer.kt
index 90dc3a0..813e0e0 100644
--- a/packages/SystemUI/src/com/android/systemui/compose/ComposeInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/compose/ComposeInitializer.kt
@@ -17,6 +17,13 @@
 package com.android.systemui.compose
 
 import android.view.View
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.findViewTreeLifecycleOwner
+import androidx.lifecycle.setViewTreeLifecycleOwner
+import androidx.savedstate.SavedStateRegistryController
+import androidx.savedstate.SavedStateRegistryOwner
+import com.android.compose.animation.ViewTreeSavedStateRegistryOwner
+import com.android.systemui.lifecycle.ViewLifecycleOwner
 
 /**
  * An initializer to use Compose outside of an Activity, e.g. inside a window added directly using
@@ -39,10 +46,55 @@
  *    }
  * ```
  */
-interface ComposeInitializer {
+object ComposeInitializer {
     /** Function to be called on your window root view's [View.onAttachedToWindow] function. */
-    fun onAttachedToWindow(root: View)
+    fun onAttachedToWindow(root: View) {
+        if (root.findViewTreeLifecycleOwner() != null) {
+            error("root $root already has a LifecycleOwner")
+        }
+
+        val parent = root.parent
+        if (parent is View && parent.id != android.R.id.content) {
+            error(
+                "ComposeInitializer.onAttachedToWindow(View) must be called on the content child." +
+                    "Outside of activities and dialogs, this is usually the top-most View of a " +
+                    "window."
+            )
+        }
+
+        // The lifecycle owner, which is STARTED when [root] is visible and RESUMED when [root] is
+        // both visible and focused.
+        val lifecycleOwner = ViewLifecycleOwner(root)
+
+        // We create a trivial implementation of [SavedStateRegistryOwner] that does not do any save
+        // or restore because SystemUI process is always running and top-level windows using this
+        // initializer are created once, when the process is started.
+        val savedStateRegistryOwner =
+            object : SavedStateRegistryOwner {
+                private val savedStateRegistryController =
+                    SavedStateRegistryController.create(this).apply { performRestore(null) }
+
+                override val savedStateRegistry = savedStateRegistryController.savedStateRegistry
+
+                override val lifecycle: Lifecycle
+                    get() = lifecycleOwner.lifecycle
+            }
+
+        // We must call [ViewLifecycleOwner.onCreate] after creating the [SavedStateRegistryOwner]
+        // because `onCreate` might move the lifecycle state to STARTED which will make
+        // [SavedStateRegistryController.performRestore] throw.
+        lifecycleOwner.onCreate()
+
+        // Set the owners on the root. They will be reused by any ComposeView inside the root
+        // hierarchy.
+        root.setViewTreeLifecycleOwner(lifecycleOwner)
+        ViewTreeSavedStateRegistryOwner.set(root, savedStateRegistryOwner)
+    }
 
     /** Function to be called on your window root view's [View.onDetachedFromWindow] function. */
-    fun onDetachedFromWindow(root: View)
+    fun onDetachedFromWindow(root: View) {
+        (root.findViewTreeLifecycleOwner() as ViewLifecycleOwner).onDestroy()
+        root.setViewTreeLifecycleOwner(null)
+        ViewTreeSavedStateRegistryOwner.set(root, null)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
index e8a8444..7f8103e 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -18,7 +18,7 @@
 
 import android.app.Activity
 import android.app.ActivityOptions
-import android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+import android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
 import android.app.Dialog
 import android.app.PendingIntent
 import android.content.ComponentName
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 6d9994f..ce24259 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -71,6 +71,7 @@
 import android.media.projection.IMediaProjectionManager;
 import android.media.projection.MediaProjectionManager;
 import android.media.session.MediaSessionManager;
+import android.nearby.NearbyManager;
 import android.net.ConnectivityManager;
 import android.net.NetworkScoreManager;
 import android.net.wifi.WifiManager;
@@ -441,6 +442,12 @@
 
     @Provides
     @Singleton
+    static NearbyManager provideNearbyManager(Context context) {
+        return context.getSystemService(NearbyManager.class);
+    }
+
+    @Provides
+    @Singleton
     static NetworkScoreManager provideNetworkScoreManager(Context context) {
         return context.getSystemService(NetworkScoreManager.class);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
index a90980f..a431a59 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.dagger;
 
-import com.android.systemui.globalactions.ShutdownUiModule;
 import com.android.systemui.keyguard.CustomizationProvider;
 import com.android.systemui.statusbar.NotificationInsetsModule;
 import com.android.systemui.statusbar.QsFrameTranslateModule;
@@ -32,7 +31,6 @@
         DependencyProvider.class,
         NotificationInsetsModule.class,
         QsFrameTranslateModule.class,
-        ShutdownUiModule.class,
         SystemUIBinder.class,
         SystemUIModule.class,
         SystemUICoreStartableModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index f7bc5cdc..a4011fd 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -43,6 +43,7 @@
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsImplementation;
 import com.android.systemui.rotationlock.RotationLockModule;
+import com.android.systemui.rotationlock.RotationLockNewModule;
 import com.android.systemui.scene.SceneContainerFrameworkModule;
 import com.android.systemui.screenshot.ReferenceScreenshotModule;
 import com.android.systemui.settings.MultiUserUtilsModule;
@@ -110,6 +111,7 @@
         RearDisplayModule.class,
         ReferenceScreenshotModule.class,
         RotationLockModule.class,
+        RotationLockNewModule.class,
         ScreenDecorationsModule.class,
         SystemActionsModule.class,
         ShadeModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 1157d97..19af371 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -51,6 +51,7 @@
 import com.android.systemui.controls.dagger.ControlsModule;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.SystemUser;
+import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.demomode.dagger.DemoModeModule;
 import com.android.systemui.deviceentry.DeviceEntryModule;
 import com.android.systemui.display.DisplayModule;
@@ -365,7 +366,8 @@
             SysUiState sysUiState,
             FeatureFlags featureFlags,
             NotifPipelineFlags notifPipelineFlags,
-            @Main Executor sysuiMainExecutor) {
+            @Main Executor sysuiMainExecutor,
+            @UiBackground Executor sysuiUiBgExecutor) {
         return Optional.ofNullable(BubblesManager.create(context,
                 bubblesOptional,
                 notificationShadeWindowController,
@@ -384,7 +386,8 @@
                 sysUiState,
                 featureFlags,
                 notifPipelineFlags,
-                sysuiMainExecutor));
+                sysuiMainExecutor,
+                sysuiUiBgExecutor));
     }
 
     @Binds
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt
index cf7d601..baae986 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -62,6 +62,10 @@
 import com.android.systemui.user.data.model.SelectionStatus
 import com.android.systemui.user.data.repository.UserRepository
 import com.google.errorprone.annotations.CompileTimeConstant
+import java.io.PrintWriter
+import java.util.Arrays
+import java.util.stream.Collectors
+import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
@@ -83,10 +87,6 @@
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
-import java.io.PrintWriter
-import java.util.Arrays
-import java.util.stream.Collectors
-import javax.inject.Inject
 
 /**
  * API to run face authentication and detection for device entry / on keyguard (as opposed to the
@@ -431,11 +431,11 @@
             override fun onAuthenticationFailed() {
                 _isAuthenticated.value = false
                 faceAuthLogger.authenticationFailed()
+                _authenticationStatus.value = FailedFaceAuthenticationStatus()
                 if (!_isLockedOut.value) {
                     // onAuthenticationError gets invoked before onAuthenticationFailed when the
                     // last auth attempt locks out face authentication.
-                    // Skip updating the authentication status in such a scenario.
-                    _authenticationStatus.value = FailedFaceAuthenticationStatus()
+                    // Skip onFaceAuthRequestCompleted in such a scenario.
                     onFaceAuthRequestCompleted()
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractor.kt
index 6bfe8d9..846013c 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractor.kt
@@ -21,9 +21,12 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.deviceentry.shared.model.ErrorFaceAuthenticationStatus
+import com.android.systemui.deviceentry.shared.model.FaceFailureMessage
+import com.android.systemui.deviceentry.shared.model.FaceLockoutMessage
 import com.android.systemui.deviceentry.shared.model.FaceMessage
 import com.android.systemui.deviceentry.shared.model.FaceTimeoutMessage
 import com.android.systemui.deviceentry.shared.model.FailedFaceAuthenticationStatus
+import com.android.systemui.deviceentry.shared.model.FingerprintFailureMessage
 import com.android.systemui.deviceentry.shared.model.FingerprintLockoutMessage
 import com.android.systemui.deviceentry.shared.model.FingerprintMessage
 import com.android.systemui.deviceentry.shared.model.HelpFaceAuthenticationStatus
@@ -97,11 +100,7 @@
         fingerprintAuthInteractor.fingerprintHelp
             .sample(biometricSettingsInteractor.fingerprintAuthCurrentlyAllowed, ::Pair)
             .filter { (_, fingerprintAuthAllowed) -> fingerprintAuthAllowed }
-            .map { (helpStatus, _) ->
-                FingerprintMessage(
-                    helpStatus.msg,
-                )
-            }
+            .map { (helpStatus, _) -> FingerprintMessage(helpStatus.msg) }
 
     private val fingerprintFailMessage: Flow<FingerprintMessage> =
         fingerprintPropertyInteractor.isUdfps.flatMapLatest { isUdfps ->
@@ -109,7 +108,7 @@
                 .sample(biometricSettingsInteractor.fingerprintAuthCurrentlyAllowed)
                 .filter { fingerprintAuthAllowed -> fingerprintAuthAllowed }
                 .map {
-                    FingerprintMessage(
+                    FingerprintFailureMessage(
                         if (isUdfps) {
                             resources.getString(
                                 com.android.internal.R.string.fingerprint_udfps_error_not_match
@@ -118,7 +117,7 @@
                             resources.getString(
                                 com.android.internal.R.string.fingerprint_error_not_match
                             )
-                        },
+                        }
                     )
                 }
         }
@@ -154,7 +153,7 @@
         faceFailure
             .sample(biometricSettingsInteractor.faceAuthCurrentlyAllowed)
             .filter { faceAuthCurrentlyAllowed -> faceAuthCurrentlyAllowed }
-            .map { FaceMessage(resources.getString(R.string.keyguard_face_failed)) }
+            .map { FaceFailureMessage(resources.getString(R.string.keyguard_face_failed)) }
 
     private val faceErrorMessage: Flow<FaceMessage> =
         faceError
@@ -173,6 +172,7 @@
                             FaceTimeoutMessage(status.msg)
                         }
                     }
+                    status.isLockoutError() -> FaceLockoutMessage(status.msg)
                     else -> FaceMessage(status.msg)
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
index 21fd87c..029a4f3 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
@@ -25,7 +25,7 @@
 import com.android.systemui.keyguard.data.repository.TrustRepository
 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.Scenes
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -81,9 +81,9 @@
     val isDeviceEntered: StateFlow<Boolean> =
         sceneInteractor.currentScene
             .filter { currentScene ->
-                currentScene == SceneKey.Gone || currentScene == SceneKey.Lockscreen
+                currentScene == Scenes.Gone || currentScene == Scenes.Lockscreen
             }
-            .map { it == SceneKey.Gone }
+            .map { it == Scenes.Gone }
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.Eagerly,
@@ -148,12 +148,12 @@
         applicationScope.launch {
             if (isAuthenticationRequired()) {
                 sceneInteractor.changeScene(
-                    toScene = SceneKey.Bouncer,
+                    toScene = Scenes.Bouncer,
                     loggingReason = "request to unlock device while authentication required",
                 )
             } else {
                 sceneInteractor.changeScene(
-                    toScene = SceneKey.Gone,
+                    toScene = Scenes.Gone,
                     loggingReason = "request to unlock device while authentication isn't required",
                 )
             }
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
index cf91e14..0c9fbc2 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
@@ -189,6 +189,18 @@
                 }
             }
             .launchIn(applicationScope)
+
+        facePropertyRepository.cameraInfo
+            .onEach {
+                if (it != null && isRunning()) {
+                    repository.cancel()
+                    runFaceAuth(
+                        FaceAuthUiEvent.FACE_AUTH_CAMERA_AVAILABLE_CHANGED,
+                        fallbackToDetect = true
+                    )
+                }
+            }
+            .launchIn(applicationScope)
     }
 
     private suspend fun resetLockedOutState(currentUserId: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/shared/FaceAuthReason.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/shared/FaceAuthReason.kt
index ee220d5..08a6166 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/shared/FaceAuthReason.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/shared/FaceAuthReason.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.ASSISTANT_VISIBILITY_CHANGED
 import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.AUTH_REQUEST_DURING_CANCELLATION
 import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.BIOMETRIC_ENABLED
+import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.CAMERA_AVAILABLE_CHANGED
 import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.CAMERA_LAUNCHED
 import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.DEVICE_WOKEN_UP_ON_REACH_GESTURE
 import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.DISPLAY_OFF
@@ -130,6 +131,7 @@
         "Face auth stopped because non strong biometric allowed changed"
     const val POSTURE_CHANGED = "Face auth started/stopped due to device posture changed."
     const val DISPLAY_OFF = "Face auth stopped due to display state OFF."
+    const val CAMERA_AVAILABLE_CHANGED = "Face auth started due to the available camera changed"
 }
 
 /**
@@ -221,7 +223,9 @@
     @UiEvent(doc = NON_STRONG_BIOMETRIC_ALLOWED_CHANGED)
     FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED(1256, NON_STRONG_BIOMETRIC_ALLOWED_CHANGED),
     @UiEvent(doc = ACCESSIBILITY_ACTION) FACE_AUTH_ACCESSIBILITY_ACTION(1454, ACCESSIBILITY_ACTION),
-    @UiEvent(doc = DISPLAY_OFF) FACE_AUTH_DISPLAY_OFF(1461, DISPLAY_OFF);
+    @UiEvent(doc = DISPLAY_OFF) FACE_AUTH_DISPLAY_OFF(1461, DISPLAY_OFF),
+    @UiEvent(doc = CAMERA_AVAILABLE_CHANGED)
+    FACE_AUTH_CAMERA_AVAILABLE_CHANGED(1623, CAMERA_AVAILABLE_CHANGED);
 
     override fun getId(): Int = this.id
 
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/shared/model/BiometricMessageModels.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/shared/model/BiometricMessageModels.kt
index 59c3f7f..2ced8c41 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/shared/model/BiometricMessageModels.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/shared/model/BiometricMessageModels.kt
@@ -32,9 +32,15 @@
     private val faceTimeoutMessage: String?,
 ) : FaceMessage(faceTimeoutMessage)
 
+data class FaceLockoutMessage(private val msg: String?) : FaceMessage(msg)
+
+data class FaceFailureMessage(private val msg: String) : FaceMessage(msg)
+
 /** Fingerprint biometric message */
 open class FingerprintMessage(fingerprintMessage: String?) : BiometricMessage(fingerprintMessage)
 
 data class FingerprintLockoutMessage(
     private val fingerprintLockoutMessage: String?,
 ) : FingerprintMessage(fingerprintLockoutMessage)
+
+data class FingerprintFailureMessage(private val msg: String?) : FingerprintMessage(msg)
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index 9000da3..b97bace 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -40,7 +40,6 @@
 import com.android.systemui.log.dagger.DreamLog
 import com.android.systemui.statusbar.BlurUtils
 import com.android.systemui.statusbar.CrossFadeHelper
-import com.android.systemui.statusbar.policy.ConfigurationController
 import javax.inject.Inject
 import javax.inject.Named
 import kotlinx.coroutines.launch
@@ -55,7 +54,6 @@
     private val mOverlayStateController: DreamOverlayStateController,
     @Named(DreamOverlayModule.DREAM_BLUR_RADIUS) private val mDreamBlurRadius: Int,
     private val dreamOverlayViewModel: DreamOverlayViewModel,
-    private val configController: ConfigurationController,
     @Named(DreamOverlayModule.DREAM_IN_BLUR_ANIMATION_DURATION)
     private val mDreamInBlurAnimDurationMs: Long,
     @Named(DreamOverlayModule.DREAM_IN_COMPLICATIONS_ANIMATION_DURATION)
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamOverlayViewModel.kt
index dd67a4c..bd99f4b 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamOverlayViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamOverlayViewModel.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToGlanceableHubTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel
 import com.android.systemui.res.R
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -33,16 +34,16 @@
 @Inject
 constructor(
     configurationInteractor: ConfigurationInteractor,
-    private val toGlanceableHubTransitionViewModel: DreamingToGlanceableHubTransitionViewModel,
+    toGlanceableHubTransitionViewModel: DreamingToGlanceableHubTransitionViewModel,
+    fromGlanceableHubTransitionInteractor: GlanceableHubToDreamingTransitionViewModel,
     private val toLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel,
 ) {
 
     val dreamOverlayTranslationX: Flow<Float> =
-        configurationInteractor
-            .dimensionPixelSize(R.dimen.dream_overlay_exit_x_offset)
-            .flatMapLatest { px: Int ->
-                toGlanceableHubTransitionViewModel.dreamOverlayTranslationX(px)
-            }
+        merge(
+            toGlanceableHubTransitionViewModel.dreamOverlayTranslationX,
+            fromGlanceableHubTransitionInteractor.dreamOverlayTranslationX,
+        )
 
     val dreamOverlayTranslationY: Flow<Float> =
         configurationInteractor
@@ -55,6 +56,7 @@
         merge(
             toLockscreenTransitionViewModel.dreamOverlayAlpha,
             toGlanceableHubTransitionViewModel.dreamOverlayAlpha,
+            fromGlanceableHubTransitionInteractor.dreamOverlayAlpha,
         )
 
     val transitionEnded = toLockscreenTransitionViewModel.transitionEnded
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
index 7a24d76..298da13 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
@@ -22,8 +22,10 @@
 import com.android.server.notification.Flags.crossAppPoliteNotifications
 import com.android.server.notification.Flags.politeNotifications
 import com.android.server.notification.Flags.vibrateWhileUnlocked
+import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
 import com.android.systemui.Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR
 import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT
+import com.android.systemui.Flags.communalHub
 import com.android.systemui.Flags.keyguardBottomAreaRefactor
 import com.android.systemui.Flags.migrateClocksToBlueprint
 import com.android.systemui.dagger.SysUISingleton
@@ -58,6 +60,9 @@
         // ComposeLockscreen dependencies
         ComposeLockscreen.token dependsOn keyguardBottomAreaRefactor
         ComposeLockscreen.token dependsOn migrateClocksToBlueprint
+
+        // CommunalHub dependencies
+        communalHub dependsOn migrateClocksToBlueprint
     }
 
     private inline val politeNotifications
@@ -70,4 +75,6 @@
         get() = FlagToken(FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR, keyguardBottomAreaRefactor())
     private inline val migrateClocksToBlueprint
         get() = FlagToken(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT, migrateClocksToBlueprint())
+    private inline val communalHub
+        get() = FlagToken(FLAG_COMMUNAL_HUB, communalHub())
 }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 33a69bf..6bb84649 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -369,12 +369,6 @@
     @Keep
     val WM_BUBBLE_BAR = sysPropBooleanFlag("persist.wm.debug.bubble_bar", default = false)
 
-    // TODO(b/260271148): Tracking bug
-    @Keep
-    @JvmField
-    val WM_DESKTOP_WINDOWING_2 =
-        sysPropBooleanFlag("persist.wm.debug.desktop_mode_2", default = false)
-
     // TODO(b/254513207): Tracking Bug to delete
     @Keep
     @JvmField
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java b/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java
index 51978ec..ccd69ca 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java
@@ -22,7 +22,10 @@
 import android.annotation.StringRes;
 import android.app.Dialog;
 import android.content.Context;
+import android.nearby.NearbyManager;
+import android.net.platform.flags.Flags;
 import android.os.PowerManager;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
@@ -38,6 +41,8 @@
 import com.android.systemui.statusbar.BlurUtils;
 import com.android.systemui.statusbar.phone.ScrimController;
 
+import javax.inject.Inject;
+
 /**
  * Provides the UI shown during system shutdown.
  */
@@ -45,9 +50,13 @@
 
     private Context mContext;
     private BlurUtils mBlurUtils;
-    public ShutdownUi(Context context, BlurUtils blurUtils) {
+    private NearbyManager mNearbyManager;
+
+    @Inject
+    public ShutdownUi(Context context, BlurUtils blurUtils, NearbyManager nearbyManager) {
         mContext = context;
         mBlurUtils = blurUtils;
+        mNearbyManager = nearbyManager;
     }
 
     /**
@@ -132,12 +141,28 @@
     /**
      * Returns the layout resource to use for UI while shutting down.
      * @param isReboot Whether this is a reboot or a shutdown.
-     * @return
      */
-    public int getShutdownDialogContent(boolean isReboot) {
-        return R.layout.shutdown_dialog;
+    @VisibleForTesting int getShutdownDialogContent(boolean isReboot) {
+        if (!Flags.poweredOffFindingPlatform()) {
+            return R.layout.shutdown_dialog;
+        }
+        int finderActive = mNearbyManager.getPoweredOffFindingMode();
+        if (finderActive == NearbyManager.POWERED_OFF_FINDING_MODE_DISABLED
+                || finderActive == NearbyManager.POWERED_OFF_FINDING_MODE_UNSUPPORTED) {
+            // inactive or unsupported, use regular shutdown dialog
+            return R.layout.shutdown_dialog;
+        } else if (finderActive == NearbyManager.POWERED_OFF_FINDING_MODE_ENABLED) {
+            // active, use dialog with finder info if shutting down
+            return isReboot ? R.layout.shutdown_dialog :
+                    com.android.systemui.res.R.layout.shutdown_dialog_finder_active;
+        } else {
+            // that's weird? default to regular dialog
+            Log.w("ShutdownUi", "Unexpected value for finder active: " + finderActive);
+            return R.layout.shutdown_dialog;
+        }
     }
 
+
     @StringRes
     @VisibleForTesting int getRebootMessage(boolean isReboot, @Nullable String reason) {
         if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUiModule.kt b/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUiModule.kt
deleted file mode 100644
index b7285da..0000000
--- a/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUiModule.kt
+++ /dev/null
@@ -1,31 +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.globalactions
-
-import android.content.Context
-import com.android.systemui.statusbar.BlurUtils
-import dagger.Module
-import dagger.Provides
-
-/** Provides the UI shown during system shutdown. */
-@Module
-class ShutdownUiModule {
-    /** Shutdown UI provider. */
-    @Provides
-    fun provideShutdownUi(context: Context?, blurUtils: BlurUtils?): ShutdownUi {
-        return ShutdownUi(context, blurUtils)
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeyDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeyDialogFactory.kt
index 3ed58a7..89433d3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeyDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeyDialogFactory.kt
@@ -20,15 +20,16 @@
 import android.content.Context
 import android.view.Gravity
 import android.view.Window
+import android.view.WindowInsets
 import android.view.WindowManager
 import android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND
 import android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
 import android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
 import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL
 import androidx.activity.ComponentDialog
-import com.android.systemui.compose.ComposeFacade
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyboard.stickykeys.ui.view.createStickyKeyIndicatorView
 import com.android.systemui.keyboard.stickykeys.ui.viewmodel.StickyKeysIndicatorViewModel
 import com.android.systemui.res.R
 import javax.inject.Inject
@@ -45,10 +46,10 @@
     }
 
     private fun createStickyKeyIndicator(viewModel: StickyKeysIndicatorViewModel): Dialog {
-        return ComponentDialog(context, R.style.Theme_SystemUI_Dialog).apply {
+        return ComponentDialog(context, R.style.Theme_SystemUI_Dialog_StickyKeys).apply {
             // because we're requesting window feature it must be called before setting content
             window?.setStickyKeyWindowAttributes()
-            setContentView(ComposeFacade.createStickyKeysIndicatorContent(context, viewModel))
+            setContentView(createStickyKeyIndicatorView(context, viewModel))
         }
     }
 
@@ -61,6 +62,9 @@
         attributes =
             WindowManager.LayoutParams().apply {
                 copyFrom(attributes)
+                // needed because we're above system bars windows, see [TYPE_STATUS_BAR_SUB_PANEL]
+                receiveInsetsIgnoringZOrder = true
+                fitInsetsTypes = WindowInsets.Type.systemBars()
                 title = "StickyKeysIndicator"
             }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeysIndicatorCoordinator.kt b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeysIndicatorCoordinator.kt
index 842fd04..78c4e77 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeysIndicatorCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeysIndicatorCoordinator.kt
@@ -17,15 +17,13 @@
 package com.android.systemui.keyboard.stickykeys.ui
 
 import android.app.Dialog
-import android.util.Log
-import com.android.systemui.compose.ComposeFacade
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyboard.stickykeys.StickyKeysLogger
 import com.android.systemui.keyboard.stickykeys.ui.viewmodel.StickyKeysIndicatorViewModel
+import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
-import javax.inject.Inject
 
 @SysUISingleton
 class StickyKeysIndicatorCoordinator
@@ -40,11 +38,6 @@
     private var dialog: Dialog? = null
 
     fun startListening() {
-        // this check needs to be moved to PhysicalKeyboardCoreStartable
-        if (!ComposeFacade.isComposeAvailable()) {
-            Log.e("StickyKeysIndicatorCoordinator", "Compose is required for this UI")
-            return
-        }
         applicationScope.launch {
             viewModel.indicatorContent.collect { stickyKeys ->
                 stickyKeysLogger.logNewUiState(stickyKeys)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 301942f..106fdf1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -20,6 +20,9 @@
 import android.content.Context
 import android.view.LayoutInflater
 import android.view.View
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.ComposeView
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
 import androidx.constraintlayout.widget.ConstraintSet.END
@@ -35,7 +38,6 @@
 import com.android.systemui.CoreStartable
 import com.android.systemui.Flags.keyguardBottomAreaRefactor
 import com.android.systemui.common.ui.ConfigurationState
-import com.android.systemui.compose.ComposeFacade
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInteractor
 import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
@@ -45,6 +47,8 @@
 import com.android.systemui.keyguard.ui.binder.KeyguardBlueprintViewBinder
 import com.android.systemui.keyguard.ui.binder.KeyguardIndicationAreaBinder
 import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder
+import com.android.systemui.keyguard.ui.composable.LockscreenContent
+import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint
 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
@@ -132,7 +136,7 @@
         if (!SceneContainerFlag.isEnabled) {
             if (ComposeLockscreen.isEnabled) {
                 val composeView =
-                    ComposeFacade.createLockscreen(
+                    createLockscreen(
                         context = context,
                         viewModel = lockscreenContentViewModel,
                         blueprints = lockscreenSceneBlueprintsLazy.get(),
@@ -207,6 +211,21 @@
             )
     }
 
+    private fun createLockscreen(
+        context: Context,
+        viewModel: LockscreenContentViewModel,
+        blueprints: Set<@JvmSuppressWildcards LockscreenSceneBlueprint>,
+    ): View {
+        val sceneBlueprints =
+            blueprints.mapNotNull { it as? ComposableLockscreenSceneBlueprint }.toSet()
+        return ComposeView(context).apply {
+            setContent {
+                LockscreenContent(viewModel = viewModel, blueprints = sceneBlueprints)
+                    .Content(modifier = Modifier.fillMaxSize())
+            }
+        }
+    }
+
     /**
      * Temporary, to allow NotificationPanelViewController to use the same instance while code is
      * migrated: b/288242803
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c6b9952..6d917bb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -40,6 +40,7 @@
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
 import static com.android.systemui.DejankUtils.whitelistIpcs;
+import static com.android.systemui.Flags.notifyPowerManagerUserActivityBackground;
 import static com.android.systemui.Flags.refactorGetCurrentUser;
 import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
@@ -1488,7 +1489,11 @@
     }
 
     public void userActivity() {
-        mPM.userActivity(mSystemClock.uptimeMillis(), false);
+        if (notifyPowerManagerUserActivityBackground()) {
+            mUiBgExecutor.execute(() -> mPM.userActivity(mSystemClock.uptimeMillis(), false));
+        } else {
+            mPM.userActivity(mSystemClock.uptimeMillis(), false);
+        }
     }
 
     private void setupLocked() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
index b152eea..2bede977 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
@@ -40,6 +40,7 @@
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.buffer
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.shareIn
@@ -177,92 +178,99 @@
 
     // TODO(b/322555228) Remove after consolidating device entry auth messages with BP auth messages
     //  in BiometricStatusRepository
+    /**
+     * FingerprintAuthenticationStatus Multiple statuses may arrive in immediate sequence (ie:
+     * acquired, failed, help, error), so we use a buffer to ensure consumers receive each distinct
+     * status.
+     */
     override val authenticationStatus: Flow<FingerprintAuthenticationStatus>
-        get() = conflatedCallbackFlow {
-            val callback =
-                object : KeyguardUpdateMonitorCallback() {
-                    override fun onBiometricAuthenticated(
-                        userId: Int,
-                        biometricSourceType: BiometricSourceType,
-                        isStrongBiometric: Boolean,
-                    ) {
-                        sendUpdateIfFingerprint(
-                            biometricSourceType,
-                            SuccessFingerprintAuthenticationStatus(
-                                userId,
-                                isStrongBiometric,
-                            ),
-                        )
-                    }
+        get() =
+            conflatedCallbackFlow {
+                    val callback =
+                        object : KeyguardUpdateMonitorCallback() {
+                            override fun onBiometricAuthenticated(
+                                userId: Int,
+                                biometricSourceType: BiometricSourceType,
+                                isStrongBiometric: Boolean,
+                            ) {
+                                sendUpdateIfFingerprint(
+                                    biometricSourceType,
+                                    SuccessFingerprintAuthenticationStatus(
+                                        userId,
+                                        isStrongBiometric,
+                                    ),
+                                )
+                            }
 
-                    override fun onBiometricError(
-                        msgId: Int,
-                        errString: String?,
-                        biometricSourceType: BiometricSourceType,
-                    ) {
-                        sendUpdateIfFingerprint(
-                            biometricSourceType,
-                            ErrorFingerprintAuthenticationStatus(
-                                msgId,
-                                errString,
-                            ),
-                        )
-                    }
+                            override fun onBiometricError(
+                                msgId: Int,
+                                errString: String?,
+                                biometricSourceType: BiometricSourceType,
+                            ) {
+                                sendUpdateIfFingerprint(
+                                    biometricSourceType,
+                                    ErrorFingerprintAuthenticationStatus(
+                                        msgId,
+                                        errString,
+                                    ),
+                                )
+                            }
 
-                    override fun onBiometricHelp(
-                        msgId: Int,
-                        helpString: String?,
-                        biometricSourceType: BiometricSourceType,
-                    ) {
-                        sendUpdateIfFingerprint(
-                            biometricSourceType,
-                            HelpFingerprintAuthenticationStatus(
-                                msgId,
-                                helpString,
-                            ),
-                        )
-                    }
+                            override fun onBiometricHelp(
+                                msgId: Int,
+                                helpString: String?,
+                                biometricSourceType: BiometricSourceType,
+                            ) {
+                                sendUpdateIfFingerprint(
+                                    biometricSourceType,
+                                    HelpFingerprintAuthenticationStatus(
+                                        msgId,
+                                        helpString,
+                                    ),
+                                )
+                            }
 
-                    override fun onBiometricAuthFailed(
-                        biometricSourceType: BiometricSourceType,
-                    ) {
-                        sendUpdateIfFingerprint(
-                            biometricSourceType,
-                            FailFingerprintAuthenticationStatus,
-                        )
-                    }
+                            override fun onBiometricAuthFailed(
+                                biometricSourceType: BiometricSourceType,
+                            ) {
+                                sendUpdateIfFingerprint(
+                                    biometricSourceType,
+                                    FailFingerprintAuthenticationStatus,
+                                )
+                            }
 
-                    override fun onBiometricAcquired(
-                        biometricSourceType: BiometricSourceType,
-                        acquireInfo: Int,
-                    ) {
-                        sendUpdateIfFingerprint(
-                            biometricSourceType,
-                            AcquiredFingerprintAuthenticationStatus(
-                                AuthenticationReason.DeviceEntryAuthentication,
-                                acquireInfo
-                            ),
-                        )
-                    }
+                            override fun onBiometricAcquired(
+                                biometricSourceType: BiometricSourceType,
+                                acquireInfo: Int,
+                            ) {
+                                sendUpdateIfFingerprint(
+                                    biometricSourceType,
+                                    AcquiredFingerprintAuthenticationStatus(
+                                        AuthenticationReason.DeviceEntryAuthentication,
+                                        acquireInfo
+                                    ),
+                                )
+                            }
 
-                    private fun sendUpdateIfFingerprint(
-                        biometricSourceType: BiometricSourceType,
-                        authenticationStatus: FingerprintAuthenticationStatus
-                    ) {
-                        if (biometricSourceType != BiometricSourceType.FINGERPRINT) {
-                            return
+                            private fun sendUpdateIfFingerprint(
+                                biometricSourceType: BiometricSourceType,
+                                authenticationStatus: FingerprintAuthenticationStatus
+                            ) {
+                                if (biometricSourceType != BiometricSourceType.FINGERPRINT) {
+                                    return
+                                }
+
+                                trySendWithFailureLogging(
+                                    authenticationStatus,
+                                    TAG,
+                                    "new fingerprint authentication status"
+                                )
+                            }
                         }
-
-                        trySendWithFailureLogging(
-                            authenticationStatus,
-                            TAG,
-                            "new fingerprint authentication status"
-                        )
-                    }
+                    keyguardUpdateMonitor.registerCallback(callback)
+                    awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
                 }
-            keyguardUpdateMonitor.registerCallback(callback)
-            awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
-        }
+                .buffer(capacity = 4)
 
     override val shouldUpdateIndicatorVisibility: Flow<Boolean> =
         conflatedCallbackFlow {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
index 59288a1..7ad5aac 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
@@ -41,7 +41,6 @@
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.callbackFlow
-import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.mapNotNull
 import kotlinx.coroutines.flow.onStart
@@ -60,7 +59,7 @@
 
     val currentClock: StateFlow<ClockController?>
 
-    val previewClock: StateFlow<ClockController>
+    val previewClockPair: StateFlow<Pair<ClockController, ClockController>>
 
     val clockEventController: ClockEventController
     fun setClockSize(@ClockSize size: Int)
@@ -111,7 +110,6 @@
                 awaitClose { clockRegistry.unregisterClockChangeListener(listener) }
             }
             .mapNotNull { it }
-            .distinctUntilChanged()
 
     override val currentClock: StateFlow<ClockController?> =
         currentClockId
@@ -122,13 +120,14 @@
                 initialValue = clockRegistry.createCurrentClock()
             )
 
-    override val previewClock: StateFlow<ClockController> =
+    override val previewClockPair: StateFlow<Pair<ClockController, ClockController>> =
         currentClockId
-            .map { clockRegistry.createCurrentClock() }
+            .map { Pair(clockRegistry.createCurrentClock(), clockRegistry.createCurrentClock()) }
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.WhileSubscribed(),
-                initialValue = clockRegistry.createCurrentClock()
+                initialValue =
+                    Pair(clockRegistry.createCurrentClock(), clockRegistry.createCurrentClock())
             )
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index 0cf74a1..6aed944 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -31,8 +31,8 @@
 import kotlin.time.Duration.Companion.milliseconds
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.FlowPreview
-import kotlinx.coroutines.flow.sample
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
 
 @SysUISingleton
@@ -62,7 +62,6 @@
         listenForTransitionToCamera(scope, keyguardInteractor)
     }
 
-    @FlowPreview
     private fun listenForAlternateBouncerToLockscreenHubAodOrDozing() {
         scope.launch {
             keyguardInteractor.alternateBouncerShowing
@@ -71,7 +70,7 @@
                 // happening prematurely.
                 // This should eventually be removed in favor of
                 // [KeyguardTransitionInteractor#startDismissKeyguardTransition]
-                .sample(150L)
+                .onEach { delay(150L) }
                 .sampleCombine(
                     keyguardInteractor.primaryBouncerShowing,
                     startedKeyguardTransitionStep,
@@ -156,5 +155,6 @@
         val TO_GONE_DURATION = 500.milliseconds
         val TO_AOD_DURATION = TRANSITION_DURATION_MS
         val TO_PRIMARY_BOUNCER_DURATION = TRANSITION_DURATION_MS
+        val TO_DOZING_DURATION = TRANSITION_DURATION_MS
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index e0b5c0e..dbd5e26 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -27,12 +27,14 @@
 import com.android.systemui.keyguard.shared.model.DozeStateModel
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
+import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.util.kotlin.Utils.Companion.sample
 import com.android.systemui.util.kotlin.sample
 import javax.inject.Inject
 import kotlin.time.Duration.Companion.milliseconds
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.debounce
 import kotlinx.coroutines.launch
 
 @SysUISingleton
@@ -45,6 +47,7 @@
     @Background bgDispatcher: CoroutineDispatcher,
     @Main mainDispatcher: CoroutineDispatcher,
     private val keyguardInteractor: KeyguardInteractor,
+    private val powerInteractor: PowerInteractor,
 ) :
     TransitionInteractor(
         fromState = KeyguardState.AOD,
@@ -68,15 +71,16 @@
      */
     private fun listenForAodToOccluded() {
         scope.launch {
-            keyguardInteractor.isKeyguardOccluded.sample(startedKeyguardState, ::Pair).collect {
-                (isOccluded, startedKeyguardState) ->
-                if (isOccluded && startedKeyguardState == KeyguardState.AOD) {
-                    startTransitionTo(
-                        toState = KeyguardState.OCCLUDED,
-                        modeOnCanceled = TransitionModeOnCanceled.RESET
-                    )
+            keyguardInteractor.isKeyguardOccluded
+                .sample(startedKeyguardTransitionStep, ::Pair)
+                .collect { (isOccluded, lastStartedStep) ->
+                    if (isOccluded && lastStartedStep.to == KeyguardState.AOD) {
+                        startTransitionTo(
+                            toState = KeyguardState.OCCLUDED,
+                            modeOnCanceled = TransitionModeOnCanceled.RESET
+                        )
+                    }
                 }
-            }
         }
     }
 
@@ -85,15 +89,26 @@
             keyguardInteractor
                 .dozeTransitionTo(DozeStateModel.FINISH)
                 .sample(
+                    keyguardInteractor.isKeyguardShowing,
                     startedKeyguardTransitionStep,
                     keyguardInteractor.isKeyguardOccluded,
                     keyguardInteractor.biometricUnlockState,
+                    keyguardInteractor.primaryBouncerShowing,
                 )
-                .collect { (_, lastStartedStep, occluded, biometricUnlockState) ->
+                .collect {
+                    (
+                        _,
+                        isKeyguardShowing,
+                        lastStartedStep,
+                        occluded,
+                        biometricUnlockState,
+                        primaryBouncerShowing) ->
                     if (
                         lastStartedStep.to == KeyguardState.AOD &&
                             !occluded &&
-                            !isWakeAndUnlock(biometricUnlockState)
+                            !isWakeAndUnlock(biometricUnlockState) &&
+                            isKeyguardShowing &&
+                            !primaryBouncerShowing
                     ) {
                         val modeOnCanceled =
                             if (lastStartedStep.from == KeyguardState.LOCKSCREEN) {
@@ -134,13 +149,31 @@
         }
 
         scope.launch {
-            keyguardInteractor.biometricUnlockState.sample(finishedKeyguardState, ::Pair).collect {
-                (biometricUnlockState, keyguardState) ->
-                KeyguardWmStateRefactor.assertInLegacyMode()
-                if (keyguardState == KeyguardState.AOD && isWakeAndUnlock(biometricUnlockState)) {
-                    startTransitionTo(KeyguardState.GONE)
+            powerInteractor.isAwake
+                .debounce(50L)
+                .sample(
+                    keyguardInteractor.biometricUnlockState,
+                    startedKeyguardTransitionStep,
+                    keyguardInteractor.isKeyguardShowing,
+                    keyguardInteractor.isKeyguardDismissible,
+                )
+                .collect {
+                    (
+                        isAwake,
+                        biometricUnlockState,
+                        lastStartedTransitionStep,
+                        isKeyguardShowing,
+                        isKeyguardDismissible) ->
+                    KeyguardWmStateRefactor.assertInLegacyMode()
+                    if (
+                        isAwake &&
+                            lastStartedTransitionStep.to == KeyguardState.AOD &&
+                            (isWakeAndUnlock(biometricUnlockState) ||
+                                (!isKeyguardShowing && isKeyguardDismissible))
+                    ) {
+                        startTransitionTo(KeyguardState.GONE)
+                    }
                 }
-            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index e2a8b6c..8591fe7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -26,13 +26,14 @@
 import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.Companion.isWakeAndUnlock
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.power.domain.interactor.PowerInteractor
-import com.android.systemui.util.kotlin.Utils.Companion.toQuad
-import com.android.systemui.util.kotlin.sample
+import com.android.systemui.util.kotlin.Utils.Companion.sample
 import javax.inject.Inject
 import kotlin.time.Duration.Companion.milliseconds
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.debounce
 import kotlinx.coroutines.launch
 
 @SysUISingleton
@@ -56,50 +57,57 @@
     ) {
 
     override fun start() {
-        listenForDozingToLockscreenHubOrOccluded()
-        listenForDozingToGone()
+        listenForDozingToAny()
         listenForTransitionToCamera(scope, keyguardInteractor)
     }
 
-    private fun listenForDozingToLockscreenHubOrOccluded() {
+    private val canDismissLockScreen: Flow<Boolean> =
+        combine(
+            keyguardInteractor.isKeyguardShowing,
+            keyguardInteractor.isKeyguardDismissible,
+        ) { isKeyguardShowing, isKeyguardDismissible ->
+            isKeyguardDismissible && !isKeyguardShowing
+        }
+
+    private fun listenForDozingToAny() {
         scope.launch {
             powerInteractor.isAwake
+                .debounce(50L)
                 .sample(
-                    combine(
-                        startedKeyguardTransitionStep,
-                        keyguardInteractor.isKeyguardOccluded,
-                        communalInteractor.isIdleOnCommunal,
-                        ::Triple
-                    ),
-                    ::toQuad
+                    keyguardInteractor.biometricUnlockState,
+                    startedKeyguardTransitionStep,
+                    keyguardInteractor.isKeyguardOccluded,
+                    communalInteractor.isIdleOnCommunal,
+                    canDismissLockScreen,
+                    keyguardInteractor.primaryBouncerShowing,
                 )
-                .collect { (isAwake, lastStartedTransition, occluded, isIdleOnCommunal) ->
-                    if (isAwake && lastStartedTransition.to == KeyguardState.DOZING) {
-                        startTransitionTo(
-                            if (occluded) {
-                                KeyguardState.OCCLUDED
-                            } else if (isIdleOnCommunal) {
-                                KeyguardState.GLANCEABLE_HUB
-                            } else {
-                                KeyguardState.LOCKSCREEN
-                            }
-                        )
+                .collect {
+                    (
+                        isAwake,
+                        biometricUnlockState,
+                        lastStartedTransition,
+                        occluded,
+                        isIdleOnCommunal,
+                        canDismissLockScreen,
+                        primaryBouncerShowing) ->
+                    if (!(isAwake && lastStartedTransition.to == KeyguardState.DOZING)) {
+                        return@collect
                     }
-                }
-        }
-    }
-
-    private fun listenForDozingToGone() {
-        scope.launch {
-            keyguardInteractor.biometricUnlockState
-                .sample(startedKeyguardTransitionStep, ::Pair)
-                .collect { (biometricUnlockState, lastStartedTransition) ->
-                    if (
-                        lastStartedTransition.to == KeyguardState.DOZING &&
-                            isWakeAndUnlock(biometricUnlockState)
-                    ) {
-                        startTransitionTo(KeyguardState.GONE)
-                    }
+                    startTransitionTo(
+                        if (isWakeAndUnlock(biometricUnlockState)) {
+                            KeyguardState.GONE
+                        } else if (canDismissLockScreen) {
+                            KeyguardState.GONE
+                        } else if (primaryBouncerShowing) {
+                            KeyguardState.PRIMARY_BOUNCER
+                        } else if (occluded) {
+                            KeyguardState.OCCLUDED
+                        } else if (isIdleOnCommunal) {
+                            KeyguardState.GLANCEABLE_HUB
+                        } else {
+                            KeyguardState.LOCKSCREEN
+                        }
+                    )
                 }
         }
     }
@@ -115,5 +123,7 @@
         const val TAG = "FromDozingTransitionInteractor"
         private val DEFAULT_DURATION = 500.milliseconds
         val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION
+        val TO_GONE_DURATION = DEFAULT_DURATION
+        val TO_PRIMARY_BOUNCER_DURATION = DEFAULT_DURATION
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index c6594ef..acfa107 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -18,6 +18,7 @@
 
 import android.animation.ValueAnimator
 import com.android.app.animation.Interpolators
+import com.android.app.tracing.coroutines.launch
 import com.android.systemui.Flags.communalHub
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
@@ -64,12 +65,13 @@
 
     private fun listenForDreamingToGlanceableHub() {
         if (!communalHub()) return
-        glanceableHubTransitions.listenForGlanceableHubTransition(
-            transitionName = "listenForDreamingToGlanceableHub",
-            transitionOwnerName = TAG,
-            fromState = KeyguardState.DREAMING,
-            toState = KeyguardState.GLANCEABLE_HUB,
-        )
+        scope.launch("$TAG#listenForDreamingToGlanceableHub", mainDispatcher) {
+            glanceableHubTransitions.listenForGlanceableHubTransition(
+                transitionOwnerName = TAG,
+                fromState = KeyguardState.DREAMING,
+                toState = KeyguardState.GLANCEABLE_HUB,
+            )
+        }
     }
 
     fun startToLockscreenTransition() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
index fbf195e..786c3c6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
@@ -27,13 +27,16 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
 import com.android.systemui.power.domain.interactor.PowerInteractor
-import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleMultiple
+import com.android.systemui.util.kotlin.BooleanFlowOperators.and
+import com.android.systemui.util.kotlin.BooleanFlowOperators.not
 import com.android.systemui.util.kotlin.sample
 import javax.inject.Inject
 import kotlin.time.Duration.Companion.seconds
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
 
 @SysUISingleton
 class FromGlanceableHubTransitionInteractor
@@ -58,13 +61,12 @@
         if (!Flags.communalHub()) {
             return
         }
-        listenForHubToLockscreen()
+        listenForHubToLockscreenOrDreaming()
         listenForHubToDozing()
         listenForHubToPrimaryBouncer()
         listenForHubToAlternateBouncer()
         listenForHubToOccluded()
         listenForHubToGone()
-        listenForHubToDreaming()
     }
 
     override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
@@ -82,13 +84,24 @@
      * Listens for the glanceable hub transition to lock screen and directly drives the keyguard
      * transition.
      */
-    private fun listenForHubToLockscreen() {
-        glanceableHubTransitions.listenForGlanceableHubTransition(
-            transitionName = "listenForHubToLockscreen",
-            transitionOwnerName = TAG,
-            fromState = KeyguardState.GLANCEABLE_HUB,
-            toState = KeyguardState.LOCKSCREEN,
-        )
+    private fun listenForHubToLockscreenOrDreaming() {
+        scope.launch("$TAG#listenForGlanceableHubToLockscreenOrDream") {
+            keyguardInteractor.isDreaming.collectLatest { dreaming ->
+                withContext(mainDispatcher) {
+                    val toState =
+                        if (dreaming) {
+                            KeyguardState.DREAMING
+                        } else {
+                            KeyguardState.LOCKSCREEN
+                        }
+                    glanceableHubTransitions.listenForGlanceableHubTransition(
+                        transitionOwnerName = TAG,
+                        fromState = KeyguardState.GLANCEABLE_HUB,
+                        toState = toState,
+                    )
+                }
+            }
+        }
     }
 
     private fun listenForHubToPrimaryBouncer() {
@@ -137,31 +150,15 @@
         }
     }
 
-    private fun listenForHubToDreaming() {
-        val invalidFromStates = setOf(KeyguardState.AOD, KeyguardState.DOZING)
-        scope.launch("$TAG#listenForHubToDreaming") {
-            keyguardInteractor.isAbleToDream
-                .sampleMultiple(startedKeyguardTransitionStep, finishedKeyguardState)
-                .collect { (isAbleToDream, lastStartedTransition, finishedKeyguardState) ->
-                    val isOnHub = finishedKeyguardState == KeyguardState.GLANCEABLE_HUB
-                    val isTransitionInterruptible =
-                        lastStartedTransition.to == KeyguardState.GLANCEABLE_HUB &&
-                            !invalidFromStates.contains(lastStartedTransition.from)
-                    if (isAbleToDream && (isOnHub || isTransitionInterruptible)) {
-                        startTransitionTo(KeyguardState.DREAMING)
-                    }
-                }
-        }
-    }
-
     private fun listenForHubToOccluded() {
         scope.launch {
-            keyguardInteractor.isKeyguardOccluded.sample(startedKeyguardState, ::Pair).collect {
-                (isOccluded, keyguardState) ->
-                if (isOccluded && keyguardState == fromState) {
-                    startTransitionTo(KeyguardState.OCCLUDED)
+            and(keyguardInteractor.isKeyguardOccluded, not(keyguardInteractor.isDreaming))
+                .sample(startedKeyguardState, ::Pair)
+                .collect { (isOccludedAndNotDreaming, keyguardState) ->
+                    if (isOccludedAndNotDreaming && keyguardState == fromState) {
+                        startTransitionTo(KeyguardState.OCCLUDED)
+                    }
                 }
-            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 40b2c63..cb1571e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -44,6 +44,7 @@
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onStart
 import kotlinx.coroutines.launch
@@ -287,7 +288,7 @@
         if (KeyguardWmStateRefactor.isEnabled) {
             // When the refactor is enabled, we no longer use isKeyguardGoingAway.
             scope.launch {
-                swipeToDismissInteractor.dismissFling.collect { _ ->
+                swipeToDismissInteractor.dismissFling.filterNotNull().collect { _ ->
                     startTransitionTo(KeyguardState.GONE)
                 }
             }
@@ -360,13 +361,13 @@
         if (!com.android.systemui.Flags.communalHub()) {
             return
         }
-
-        glanceableHubTransitions.listenForGlanceableHubTransition(
-            transitionName = "listenForLockscreenToGlanceableHub",
-            transitionOwnerName = TAG,
-            fromState = KeyguardState.LOCKSCREEN,
-            toState = KeyguardState.GLANCEABLE_HUB,
-        )
+        scope.launch(mainDispatcher) {
+            glanceableHubTransitions.listenForGlanceableHubTransition(
+                transitionOwnerName = TAG,
+                fromState = KeyguardState.LOCKSCREEN,
+                toState = KeyguardState.GLANCEABLE_HUB,
+            )
+        }
     }
 
     override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index f45a9ec..c5a2846 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -274,5 +274,6 @@
         val TO_GONE_SHORT_DURATION = 200.milliseconds
         val TO_AOD_DURATION = DEFAULT_DURATION
         val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION
+        val TO_DOZING_DURATION = DEFAULT_DURATION
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt
index 809c0aee..7443010 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt
@@ -18,11 +18,9 @@
 
 import android.animation.ValueAnimator
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.domain.interactor.CommunalTransitionProgress
-import com.android.systemui.communal.shared.model.CommunalSceneKey
-import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -32,13 +30,11 @@
 import java.util.UUID
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.flowOn
 
 class GlanceableHubTransitions
 @Inject
 constructor(
-    @Application private val scope: CoroutineScope,
     @Background private val bgDispatcher: CoroutineDispatcher,
     private val transitionInteractor: KeyguardTransitionInteractor,
     private val transitionRepository: KeyguardTransitionRepository,
@@ -52,105 +48,101 @@
      * externally. The progress is used for both transitions caused by user touch input or by
      * programmatic changes.
      */
-    fun listenForGlanceableHubTransition(
-        transitionName: String,
+    suspend fun listenForGlanceableHubTransition(
         transitionOwnerName: String,
         fromState: KeyguardState,
         toState: KeyguardState,
     ) {
         val toScene =
-            if (toState == KeyguardState.GLANCEABLE_HUB) {
-                CommunalSceneKey.Communal
+            if (fromState == KeyguardState.GLANCEABLE_HUB) {
+                CommunalScenes.Blank
             } else {
-                CommunalSceneKey.Blank
+                CommunalScenes.Communal
             }
         var transitionId: UUID? = null
-        scope.launch("$transitionOwnerName#$transitionName") {
-            communalInteractor
-                .transitionProgressToScene(toScene)
-                .sample(
-                    transitionInteractor.startedKeyguardTransitionStep.flowOn(bgDispatcher),
-                    ::Pair
-                )
-                .collect { pair ->
-                    val (transitionProgress, lastStartedStep) = pair
 
-                    val id = transitionId
-                    if (id == null) {
-                        // No transition started.
-                        if (
-                            transitionProgress is CommunalTransitionProgress.Transition &&
-                                lastStartedStep.to == fromState
-                        ) {
-                            transitionId =
-                                transitionRepository.startTransition(
-                                    TransitionInfo(
-                                        ownerName = transitionOwnerName,
-                                        from = fromState,
-                                        to = toState,
-                                        animator = null, // transition will be manually controlled
-                                    )
+        communalInteractor
+            .transitionProgressToScene(toScene)
+            .sample(
+                transitionInteractor.startedKeyguardTransitionStep.flowOn(bgDispatcher),
+                ::Pair,
+            )
+            .collect { (transitionProgress, lastStartedStep) ->
+                val id = transitionId
+                if (id == null) {
+                    // No transition started.
+                    if (
+                        transitionProgress is CommunalTransitionProgress.Transition &&
+                            lastStartedStep.to == fromState
+                    ) {
+                        transitionId =
+                            transitionRepository.startTransition(
+                                TransitionInfo(
+                                    ownerName = transitionOwnerName,
+                                    from = fromState,
+                                    to = toState,
+                                    animator = null, // transition will be manually controlled
                                 )
-                        }
-                    } else {
-                        if (lastStartedStep.to != toState) {
-                            return@collect
-                        }
-                        // An existing `id` means a transition is started, and calls to
-                        // `updateTransition` will control it until FINISHED or CANCELED
-                        val nextState: TransitionState
-                        val progressFraction: Float
-                        when (transitionProgress) {
-                            is CommunalTransitionProgress.Idle -> {
-                                if (transitionProgress.scene == toScene) {
-                                    nextState = TransitionState.FINISHED
-                                    progressFraction = 1f
-                                } else {
-                                    nextState = TransitionState.CANCELED
-                                    progressFraction = 0f
-                                }
-                            }
-                            is CommunalTransitionProgress.Transition -> {
-                                nextState = TransitionState.RUNNING
-                                progressFraction = transitionProgress.progress
-                            }
-                            is CommunalTransitionProgress.OtherTransition -> {
-                                // Shouldn't happen but if another transition starts during the
-                                // current one, mark the current one as canceled.
+                            )
+                    }
+                } else {
+                    if (lastStartedStep.to != toState) {
+                        return@collect
+                    }
+                    // An existing `id` means a transition is started, and calls to
+                    // `updateTransition` will control it until FINISHED or CANCELED
+                    val nextState: TransitionState
+                    val progressFraction: Float
+                    when (transitionProgress) {
+                        is CommunalTransitionProgress.Idle -> {
+                            if (transitionProgress.scene == toScene) {
+                                nextState = TransitionState.FINISHED
+                                progressFraction = 1f
+                            } else {
                                 nextState = TransitionState.CANCELED
                                 progressFraction = 0f
                             }
                         }
-                        transitionRepository.updateTransition(
-                            id,
-                            progressFraction,
-                            nextState,
-                        )
-
-                        if (
-                            nextState == TransitionState.CANCELED ||
-                                nextState == TransitionState.FINISHED
-                        ) {
-                            transitionId = null
+                        is CommunalTransitionProgress.Transition -> {
+                            nextState = TransitionState.RUNNING
+                            progressFraction = transitionProgress.progress
                         }
-
-                        // If canceled, just put the state back.
-                        if (nextState == TransitionState.CANCELED) {
-                            transitionRepository.startTransition(
-                                TransitionInfo(
-                                    ownerName = transitionOwnerName,
-                                    from = toState,
-                                    to = fromState,
-                                    animator =
-                                        ValueAnimator().apply {
-                                            interpolator = Interpolators.LINEAR
-                                            duration = 0
-                                        }
-                                )
-                            )
+                        is CommunalTransitionProgress.OtherTransition -> {
+                            // Shouldn't happen but if another transition starts during the
+                            // current one, mark the current one as canceled.
+                            nextState = TransitionState.CANCELED
+                            progressFraction = 0f
                         }
                     }
+                    transitionRepository.updateTransition(
+                        id,
+                        progressFraction,
+                        nextState,
+                    )
+
+                    if (
+                        nextState == TransitionState.CANCELED ||
+                            nextState == TransitionState.FINISHED
+                    ) {
+                        transitionId = null
+                    }
+
+                    // If canceled, just put the state back.
+                    if (nextState == TransitionState.CANCELED) {
+                        transitionRepository.startTransition(
+                            TransitionInfo(
+                                ownerName = transitionOwnerName,
+                                from = toState,
+                                to = fromState,
+                                animator =
+                                    ValueAnimator().apply {
+                                        interpolator = Interpolators.LINEAR
+                                        duration = 0
+                                    }
+                            )
+                        )
+                    }
                 }
-        }
+            }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
index 196770a..2cf9156 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
@@ -44,7 +44,8 @@
 
     val currentClock: StateFlow<ClockController?> = keyguardClockRepository.currentClock
 
-    val previewClock: StateFlow<ClockController> = keyguardClockRepository.previewClock
+    val previewClockPair: StateFlow<Pair<ClockController, ClockController>> =
+        keyguardClockRepository.previewClockPair
 
     var clock: ClockController? by keyguardClockRepository.clockEventController::clock
 
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 78749ea..5410b10 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
@@ -43,7 +43,7 @@
 import com.android.systemui.res.R
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.flag.SceneContainerFlags
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.data.repository.ShadeRepository
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.util.kotlin.sample
@@ -292,7 +292,7 @@
             sceneInteractorProvider
                 .get()
                 .transitioningTo
-                .map { it == SceneKey.Lockscreen }
+                .map { it == Scenes.Lockscreen }
                 .distinctUntilChanged()
                 .flatMapLatest { isTransitioningToLockscreenScene ->
                     if (isTransitioningToLockscreenScene) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
index a03fa38..d81f1f1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -21,6 +21,8 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.log.core.LogLevel.VERBOSE
 import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
@@ -37,6 +39,8 @@
     private val keyguardInteractor: KeyguardInteractor,
     private val logger: KeyguardLogger,
     private val powerInteractor: PowerInteractor,
+    private val sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
+    private val shadeInteractor: ShadeInteractor,
 ) {
 
     fun start() {
@@ -47,6 +51,30 @@
         }
 
         scope.launch {
+            sharedNotificationContainerViewModel
+                .getMaxNotifications { height, useExtraShelfSpace -> height.toInt() }
+                .collect { logger.log(TAG, VERBOSE, "Notif: max height in px", it) }
+        }
+
+        scope.launch {
+            sharedNotificationContainerViewModel.isOnLockscreen.collect {
+                logger.log(TAG, VERBOSE, "Notif: isOnLockscreen", it)
+            }
+        }
+
+        scope.launch {
+            shadeInteractor.isUserInteracting.collect {
+                logger.log(TAG, VERBOSE, "Shade: isUserInteracting", it)
+            }
+        }
+
+        scope.launch {
+            sharedNotificationContainerViewModel.isOnLockscreenWithoutShade.collect {
+                logger.log(TAG, VERBOSE, "Notif: isOnLockscreenWithoutShade", it)
+            }
+        }
+
+        scope.launch {
             keyguardInteractor.primaryBouncerShowing.collect {
                 logger.log(TAG, VERBOSE, "Primary bouncer showing", it)
             }
@@ -75,6 +103,18 @@
         }
 
         scope.launch {
+            keyguardInteractor.isKeyguardDismissible.collect {
+                logger.log(TAG, VERBOSE, "isDismissible", it)
+            }
+        }
+
+        scope.launch {
+            keyguardInteractor.isKeyguardShowing.collect {
+                logger.log(TAG, VERBOSE, "isShowing", it)
+            }
+        }
+
+        scope.launch {
             keyguardInteractor.dozeTransitionModel.collect {
                 logger.log(TAG, VERBOSE, "Doze transition", it)
             }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index d1fd719..37b331c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -35,6 +35,7 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.util.kotlin.pairwise
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -45,8 +46,8 @@
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.mapLatest
-import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.flow.stateIn
 
 /** Encapsulates business-logic related to the keyguard transitions. */
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -177,10 +178,16 @@
      * Lockscreen (0f).
      */
     val dozeAmountTransition: Flow<TransitionStep> =
-        merge(
-            aodToLockscreenTransition.map { step -> step.copy(value = 1f - step.value) },
-            lockscreenToAodTransition,
-        )
+        repository.transitions
+            .filter { step -> step.from == AOD || step.to == AOD }
+            .map { step ->
+                if (step.from == AOD) {
+                    step.copy(value = 1 - step.value)
+                } else {
+                    step
+                }
+            }
+            .shareIn(scope, SharingStarted.Eagerly, replay = 1)
 
     /** The last [TransitionStep] with a [TransitionState] of STARTED */
     val startedKeyguardTransitionStep: Flow<TransitionStep> =
@@ -201,6 +208,21 @@
             .shareIn(scope, SharingStarted.Eagerly, replay = 1)
 
     /**
+     * A pair of the most recent STARTED step, and the transition step immediately preceding it. The
+     * transition framework enforces that the previous step is either a CANCELED or FINISHED step,
+     * and that the previous step was *to* the state the STARTED step is *from*.
+     *
+     * This flow can be used to access the previous step to determine whether it was CANCELED or
+     * FINISHED. In the case of a CANCELED step, we can also figure out which state we were coming
+     * from when we were canceled.
+     */
+    val startedStepWithPrecedingStep =
+        transitions
+            .pairwise()
+            .filter { it.newValue.transitionState == TransitionState.STARTED }
+            .stateIn(scope, SharingStarted.Eagerly, null)
+
+    /**
      * The last [KeyguardState] to which we [TransitionState.FINISHED] a transition.
      *
      * WARNING: This will NOT emit a value if a transition is CANCELED, and will also not emit a
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
index b81793e..cff74b3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
@@ -19,7 +19,9 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
 import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
+import com.android.systemui.util.kotlin.sample
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
@@ -121,19 +123,27 @@
      * want to know if the AOD/clock/notifs/etc. are visible.
      */
     val lockscreenVisibility: Flow<Boolean> =
-        combine(
-                transitionInteractor.startedKeyguardTransitionStep,
-                transitionInteractor.finishedKeyguardState,
-            ) { startedStep, finishedState ->
-                // If we finished the transition, use the finished state. If we're running a
-                // transition, use the state we're transitioning FROM. This can be different from
-                // the last finished state if a transition is interrupted. For example, if we were
-                // transitioning from GONE to AOD and then started AOD -> LOCKSCREEN mid-transition,
-                // we want to immediately use the visibility for AOD (lockscreenVisibility=true)
-                // even though the lastFinishedState is still GONE (lockscreenVisibility=false).
-                if (finishedState == startedStep.to) finishedState else startedStep.from
+        transitionInteractor.currentKeyguardState
+            .sample(transitionInteractor.startedStepWithPrecedingStep, ::Pair)
+            .map { (currentState, startedWithPrev) ->
+                val startedFromStep = startedWithPrev?.previousValue
+                val startedStep = startedWithPrev?.newValue
+                val returningToGoneAfterCancellation =
+                    startedStep?.to == KeyguardState.GONE &&
+                        startedFromStep?.transitionState == TransitionState.CANCELED &&
+                        startedFromStep.from == KeyguardState.GONE
+
+                if (!returningToGoneAfterCancellation) {
+                    // By default, apply the lockscreen visibility of the current state.
+                    KeyguardState.lockscreenVisibleInState(currentState)
+                } else {
+                    // If we're transitioning to GONE after a prior canceled transition from GONE,
+                    // then this is the camera launch transition from an asleep state back to GONE.
+                    // We don't want to show the lockscreen since we're aborting the lock and going
+                    // back to GONE.
+                    KeyguardState.lockscreenVisibleInState(KeyguardState.GONE)
+                }
             }
-            .map(KeyguardState::lockscreenVisibleInState)
             .distinctUntilChanged()
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/ComposeLockscreen.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/ComposeLockscreen.kt
index 7f0b483..601fbfa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/ComposeLockscreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/ComposeLockscreen.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.keyguard.shared
 
 import com.android.systemui.Flags
-import com.android.systemui.compose.ComposeFacade
 import com.android.systemui.flags.FlagToken
 import com.android.systemui.flags.RefactorFlagUtils
 
@@ -34,7 +33,7 @@
     /** Is the refactor enabled */
     @JvmStatic
     inline val isEnabled
-        get() = Flags.composeLockscreen() && ComposeFacade.isComposeAvailable()
+        get() = Flags.composeLockscreen()
 
     /**
      * Called to ensure code is only run when the flag is enabled. This protects users from the
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
index d0821c9..f46a207 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
@@ -22,14 +22,12 @@
 import android.util.StateSet
 import android.view.HapticFeedbackConstants
 import android.view.View
-import androidx.constraintlayout.widget.ConstraintLayout
-import androidx.constraintlayout.widget.ConstraintSet
+import androidx.core.view.isInvisible
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.systemui.common.ui.view.LongPressHandlingView
 import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
-import com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntrySection
 import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryBackgroundViewModel
 import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel
 import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel
@@ -54,8 +52,6 @@
     @JvmStatic
     fun bind(
         applicationScope: CoroutineScope,
-        keyguardRootView: ConstraintLayout,
-        section: DefaultDeviceEntrySection,
         view: DeviceEntryIconView,
         viewModel: DeviceEntryIconViewModel,
         fgViewModel: DeviceEntryForegroundViewModel,
@@ -81,29 +77,17 @@
                 }
             }
 
-        keyguardRootView.repeatWhenAttached {
-            repeatOnLifecycle(Lifecycle.State.STARTED) {
-                launch {
-                    viewModel.positionAtUdfpsLocation.collect { supportsUdfps ->
-                        section.removeViews(keyguardRootView)
-                        keyguardRootView.addView(view)
-                        val constraintSet = ConstraintSet().apply { clone(keyguardRootView) }
-                        section.applyConstraintsAfterPropertiesInitialized(
-                            constraintSet,
-                            supportsUdfps,
-                        )
-                        constraintSet.applyTo(keyguardRootView)
-                    }
-                }
-            }
-        }
-
         view.repeatWhenAttached {
             // Repeat on CREATED so that the view will always observe the entire
             // GONE => AOD transition (even though the view may not be visible until the middle
             // of the transition.
             repeatOnLifecycle(Lifecycle.State.CREATED) {
                 launch {
+                    viewModel.isVisible.collect { isVisible ->
+                        longPressHandlingView.isInvisible = !isVisible
+                    }
+                }
+                launch {
                     viewModel.isLongPressEnabled.collect { isEnabled ->
                         longPressHandlingView.setLongPressHandlingEnabled(isEnabled)
                     }
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 66fc995..4812e03 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,12 +36,13 @@
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
 import javax.inject.Inject
 import kotlin.math.max
 import kotlinx.coroutines.launch
 
 private const val TAG = "KeyguardBlueprintViewBinder"
-private const val DEBUG = true
+private const val DEBUG = false
 
 @SysUISingleton
 class KeyguardBlueprintViewBinder
@@ -127,6 +128,7 @@
                         runTransition(constraintLayout, transition, Config.DEFAULT) {
                             // Add and remove views of sections that are not contained by the other.
                             blueprint.replaceViews(prevBluePrint, constraintLayout)
+                            logAlphaVisibilityOfAppliedConstraintSet(cs, clockViewModel)
                             cs.applyTo(constraintLayout)
                         }
 
@@ -153,6 +155,7 @@
                             ),
                             transition,
                         ) {
+                            logAlphaVisibilityOfAppliedConstraintSet(cs, clockViewModel)
                             cs.applyTo(constraintLayout)
                         }
                         Trace.endSection()
@@ -205,4 +208,23 @@
             apply()
         }
     }
+
+    private fun logAlphaVisibilityOfAppliedConstraintSet(
+        cs: ConstraintSet,
+        viewModel: KeyguardClockViewModel
+    ) {
+        if (!DEBUG || viewModel.clock == null) return
+        val smallClockViewId = R.id.lockscreen_clock_view
+        val largeClockViewId = viewModel.clock!!.largeClock.layout.views[0].id
+        Log.i(
+            TAG,
+            "applyCsToSmallClock: vis=${cs.getVisibility(smallClockViewId)} " +
+                "alpha=${cs.getConstraint(smallClockViewId).propertySet}"
+        )
+        Log.i(
+            TAG,
+            "applyCsToLargeClock: vis=${cs.getVisibility(largeClockViewId)} " +
+                "alpha=${cs.getConstraint(largeClockViewId).propertySet}"
+        )
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
index b56c998..46c354a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
@@ -72,38 +72,47 @@
     @JvmStatic
     fun bind(
         context: Context,
+        displayId: Int,
         rootView: ConstraintLayout,
         viewModel: KeyguardPreviewClockViewModel,
         clockEventController: ClockEventController,
-        updateClockAppearance: KSuspendFunction1<ClockController, Unit>
+        updateClockAppearance: KSuspendFunction1<ClockController, Unit>,
     ) {
+        // TODO(b/327668072): When this function is called multiple times, the clock view can be
+        //                    gone due to a race condition on removeView and addView.
         rootView.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.STARTED) {
                 launch {
-                    combine(viewModel.selectedClockSize, viewModel.previewClock) { _, clock ->
+                    combine(viewModel.selectedClockSize, viewModel.previewClockPair) { _, clock ->
                             clock
                         }
-                        .collect { previewClock ->
-                            viewModel.lastClock?.let { lastClock ->
-                                (lastClock.largeClock.layout.views +
-                                        lastClock.smallClock.layout.views)
+                        .collect { previewClockPair ->
+                            viewModel.lastClockPair?.let { clockPair ->
+                                (clockPair.first.largeClock.layout.views +
+                                        clockPair.first.smallClock.layout.views)
+                                    .forEach { rootView.removeView(it) }
+                                (clockPair.second.largeClock.layout.views +
+                                        clockPair.second.smallClock.layout.views)
                                     .forEach { rootView.removeView(it) }
                             }
-                            viewModel.lastClock = previewClock
-                            clockEventController.clock = previewClock
-                            updateClockAppearance(previewClock)
+                            viewModel.lastClockPair = previewClockPair
+                            val clockPreview =
+                                if (displayId == 0) previewClockPair.first
+                                else previewClockPair.second
+                            clockEventController.clock = clockPreview
+                            updateClockAppearance(clockPreview)
 
                             if (viewModel.shouldHighlightSelectedAffordance) {
-                                (previewClock.largeClock.layout.views +
-                                        previewClock.smallClock.layout.views)
+                                (clockPreview.largeClock.layout.views +
+                                        clockPreview.smallClock.layout.views)
                                     .forEach { it.alpha = KeyguardPreviewRenderer.DIM_ALPHA }
                             }
-                            previewClock.largeClock.layout.views.forEach {
+                            clockPreview.largeClock.layout.views.forEach {
                                 (it.parent as? ViewGroup)?.removeView(it)
                                 rootView.addView(it)
                             }
 
-                            previewClock.smallClock.layout.views.forEach {
+                            clockPreview.smallClock.layout.views.forEach {
                                 (it.parent as? ViewGroup)?.removeView(it)
                                 rootView.addView(it)
                             }
@@ -164,10 +173,12 @@
         viewModel: KeyguardPreviewClockViewModel
     ) {
         val cs = ConstraintSet().apply { clone(rootView) }
-        val clock = viewModel.previewClock.value
+        val clockPair = viewModel.previewClockPair.value
         applyClockDefaultConstraints(context, cs)
-        clock.largeClock.layout.applyPreviewConstraints(cs)
-        clock.smallClock.layout.applyPreviewConstraints(cs)
+        clockPair.first.largeClock.layout.applyPreviewConstraints(cs)
+        clockPair.first.smallClock.layout.applyPreviewConstraints(cs)
+        clockPair.second.largeClock.layout.applyPreviewConstraints(cs)
+        clockPair.second.smallClock.layout.applyPreviewConstraints(cs)
 
         // When selectedClockSize is the initial value, make both clocks invisible to avoid
         // flickering
@@ -185,8 +196,10 @@
             }
 
         cs.apply {
-            setVisibility(clock.largeClock.layout.views, largeClockVisibility)
-            setVisibility(clock.smallClock.layout.views, smallClockVisibility)
+            setVisibility(clockPair.first.largeClock.layout.views, largeClockVisibility)
+            setVisibility(clockPair.first.smallClock.layout.views, smallClockVisibility)
+            setVisibility(clockPair.second.largeClock.layout.views, largeClockVisibility)
+            setVisibility(clockPair.second.smallClock.layout.views, smallClockVisibility)
         }
         cs.applyTo(rootView)
     }
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 f95efaa..7c76e6a 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
@@ -408,6 +408,7 @@
             if (migrateClocksToBlueprint()) {
                 KeyguardPreviewClockViewBinder.bind(
                     context,
+                    displayId,
                     keyguardRootView,
                     clockViewModel,
                     clockController,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
index 951df5a..1abf4a6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
@@ -16,15 +16,20 @@
 package com.android.systemui.keyguard.ui.transitions
 
 import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToAodTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToDozingTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToPrimaryBouncerTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.AodToGoneTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.DozingToGoneTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.DozingToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.DozingToPrimaryBouncerTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.GoneToAodTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.GoneToDozingTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.GoneToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToAodTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDozingTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGoneTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel
@@ -32,6 +37,7 @@
 import com.android.systemui.keyguard.ui.viewmodel.OccludedToAodTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToAodTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToDozingTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToLockscreenTransitionViewModel
 import dagger.Binds
 import dagger.Module
@@ -49,6 +55,12 @@
 
     @Binds
     @IntoSet
+    abstract fun alternateBouncerToDozing(
+        impl: AlternateBouncerToDozingTransitionViewModel
+    ): DeviceEntryIconTransition
+
+    @Binds
+    @IntoSet
     abstract fun alternateBouncerToGone(
         impl: AlternateBouncerToGoneTransitionViewModel
     ): DeviceEntryIconTransition
@@ -71,12 +83,22 @@
 
     @Binds
     @IntoSet
+    abstract fun dozingToGone(impl: DozingToGoneTransitionViewModel): DeviceEntryIconTransition
+
+    @Binds
+    @IntoSet
     abstract fun dozingToLockscreen(
         impl: DozingToLockscreenTransitionViewModel
     ): DeviceEntryIconTransition
 
     @Binds
     @IntoSet
+    abstract fun dozingToPrimaryBouncer(
+        impl: DozingToPrimaryBouncerTransitionViewModel
+    ): DeviceEntryIconTransition
+
+    @Binds
+    @IntoSet
     abstract fun dreamingToLockscreen(
         impl: DreamingToLockscreenTransitionViewModel
     ): DeviceEntryIconTransition
@@ -89,6 +111,12 @@
 
     @Binds
     @IntoSet
+    abstract fun lockscreenToDozing(
+        impl: LockscreenToDozingTransitionViewModel
+    ): DeviceEntryIconTransition
+
+    @Binds
+    @IntoSet
     abstract fun lockscreenToDreaming(
         impl: LockscreenToDreamingTransitionViewModel
     ): DeviceEntryIconTransition
@@ -123,6 +151,10 @@
 
     @Binds
     @IntoSet
+    abstract fun goneToDozing(impl: GoneToDozingTransitionViewModel): DeviceEntryIconTransition
+
+    @Binds
+    @IntoSet
     abstract fun occludedToAod(impl: OccludedToAodTransitionViewModel): DeviceEntryIconTransition
 
     @Binds
@@ -139,6 +171,12 @@
 
     @Binds
     @IntoSet
+    abstract fun primaryBouncerToDozing(
+        impl: PrimaryBouncerToDozingTransitionViewModel
+    ): DeviceEntryIconTransition
+
+    @Binds
+    @IntoSet
     abstract fun primaryBouncerToLockscreen(
         impl: PrimaryBouncerToLockscreenTransitionViewModel
     ): DeviceEntryIconTransition
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
index a22671d..a183b72 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
@@ -52,6 +52,11 @@
     visibility: Int,
 ) = views.forEach { view -> this.setVisibility(view.id, visibility) }
 
+internal fun ConstraintSet.setAlpha(
+    views: Iterable<View>,
+    alpha: Float,
+) = views.forEach { view -> this.setAlpha(view.id, alpha) }
+
 open class ClockSection
 @Inject
 constructor(
@@ -101,6 +106,8 @@
         return constraintSet.apply {
             setVisibility(getTargetClockFace(clock).views, VISIBLE)
             setVisibility(getNonTargetClockFace(clock).views, GONE)
+            setAlpha(getTargetClockFace(clock).views, 1F)
+            setAlpha(getNonTargetClockFace(clock).views, 0F)
             if (!keyguardClockViewModel.useLargeClock) {
                 connect(sharedR.id.bc_smartspace_view, TOP, sharedR.id.date_smartspace_view, BOTTOM)
             }
@@ -179,7 +186,7 @@
                 context.resources.getDimensionPixelSize(customizationR.dimen.clock_padding_start) +
                     context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal)
             )
-            var smallClockTopMargin =
+            val smallClockTopMargin =
                 if (splitShadeStateController.shouldUseSplitNotificationShade(context.resources)) {
                     context.resources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin)
                 } else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
index d70ecce..3fc9b42 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
@@ -26,6 +26,7 @@
 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.Flags.keyguardBottomAreaRefactor
@@ -55,6 +56,7 @@
 @Inject
 constructor(
     @Application private val applicationScope: CoroutineScope,
+    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
     private val authController: AuthController,
     private val windowManager: WindowManager,
     private val context: Context,
@@ -67,7 +69,6 @@
     private val falsingManager: Lazy<FalsingManager>,
     private val vibratorHelper: Lazy<VibratorHelper>,
 ) : KeyguardSection() {
-    private var deviceEntryIconView: DeviceEntryIconView? = null
     private val deviceEntryIconViewId = R.id.device_entry_icon_view
 
     override fun addViews(constraintLayout: ConstraintLayout) {
@@ -79,22 +80,21 @@
             notificationPanelView.removeView(it)
         }
 
-        if (DeviceEntryUdfpsRefactor.isEnabled) {
-            deviceEntryIconView =
+        val view =
+            if (DeviceEntryUdfpsRefactor.isEnabled) {
                 DeviceEntryIconView(context, null).apply { id = deviceEntryIconViewId }
-        } else {
-            // keyguardBottomAreaRefactor()
-            constraintLayout.addView(LockIconView(context, null).apply { id = R.id.lock_icon_view })
-        }
+            } else {
+                // keyguardBottomAreaRefactor()
+                LockIconView(context, null).apply { id = R.id.lock_icon_view }
+            }
+        constraintLayout.addView(view)
     }
 
     override fun bindData(constraintLayout: ConstraintLayout) {
         if (DeviceEntryUdfpsRefactor.isEnabled) {
-            deviceEntryIconView?.let {
+            constraintLayout.findViewById<DeviceEntryIconView?>(deviceEntryIconViewId)?.let {
                 DeviceEntryIconViewBinder.bind(
                     applicationScope,
-                    constraintLayout,
-                    this,
                     it,
                     deviceEntryIconViewModel.get(),
                     deviceEntryForegroundViewModel.get(),
@@ -111,22 +111,7 @@
     }
 
     override fun applyConstraints(constraintSet: ConstraintSet) {
-        if (!DeviceEntryUdfpsRefactor.isEnabled) {
-            applyConstraints(constraintSet, authController.isUdfpsSupported)
-        }
-    }
-
-    fun applyConstraintsAfterPropertiesInitialized(
-        constraintSet: ConstraintSet,
-        isUdfpsSupported: Boolean
-    ) {
-        if (DeviceEntryUdfpsRefactor.isUnexpectedlyInLegacyMode()) {
-            return
-        }
-        applyConstraints(constraintSet, isUdfpsSupported)
-    }
-
-    private fun applyConstraints(constraintSet: ConstraintSet, isUdfpsSupported: Boolean) {
+        val isUdfpsSupported = keyguardUpdateMonitor.isUdfpsSupported
         val scaleFactor: Float = authController.scaleFactor
         val mBottomPaddingPx =
             context.resources.getDimensionPixelSize(R.dimen.lock_icon_margin_bottom)
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 4bc2d86..a203c53 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
@@ -26,6 +26,7 @@
 import androidx.constraintlayout.widget.ConstraintSet.END
 import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
 import androidx.constraintlayout.widget.ConstraintSet.START
+import androidx.constraintlayout.widget.ConstraintSet.VISIBILITY_MODE_IGNORE
 import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT
 import androidx.core.view.isVisible
 import com.android.systemui.Flags.keyguardBottomAreaRefactor
@@ -103,7 +104,8 @@
                 BOTTOM,
                 resources.getDimensionPixelSize(R.dimen.keyguard_affordance_vertical_offset)
             )
-            setVisibility(R.id.keyguard_settings_button, View.GONE)
+            // Ignore ConstrainSet's default visibility, and let the view choose
+            setVisibilityMode(R.id.keyguard_settings_button, VISIBILITY_MODE_IGNORE)
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
index f65f376..6184c82 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
@@ -199,8 +199,8 @@
             private val TRANSITION_PROPERTIES =
                 arrayOf(PROP_VISIBILITY, PROP_ALPHA, PROP_BOUNDS, SMARTSPACE_BOUNDS)
 
-            private val DEBUG = true
-            private val TAG = ClockFaceInTransition::class.simpleName!!
+            private val DEBUG = false
+            private val TAG = VisibilityBoundsTransition::class.simpleName!!
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModel.kt
index b4b48a8..4fd92d7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModel.kt
@@ -25,7 +25,6 @@
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.emptyFlow
 import kotlinx.coroutines.flow.flatMapLatest
 
 /**
@@ -60,7 +59,7 @@
             if (udfpsEnrolledAndEnabled) {
                 transitionAnimation.immediatelyTransitionTo(1f)
             } else {
-                emptyFlow()
+                transitionAnimation.immediatelyTransitionTo(0f)
             }
         }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModel.kt
new file mode 100644
index 0000000..9649af73
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModel.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.domain.interactor.FromAlternateBouncerTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+
+/**
+ * Breaks down ALTERNATE BOUNCER->DOZING transition into discrete steps for corresponding views to
+ * consume.
+ */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class AlternateBouncerToDozingTransitionViewModel
+@Inject
+constructor(
+    deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+    animationFlow: KeyguardTransitionAnimationFlow,
+) : DeviceEntryIconTransition {
+    private val transitionAnimation =
+        animationFlow.setup(
+            duration = FromAlternateBouncerTransitionInteractor.TO_DOZING_DURATION,
+            from = KeyguardState.ALTERNATE_BOUNCER,
+            to = KeyguardState.DOZING,
+        )
+
+    val deviceEntryBackgroundViewAlpha: Flow<Float> =
+        transitionAnimation.immediatelyTransitionTo(0f)
+
+    override val deviceEntryParentViewAlpha: Flow<Float> =
+        deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfpsEnrolledAndEnabled
+            ->
+            if (udfpsEnrolledAndEnabled) {
+                transitionAnimation.immediatelyTransitionTo(1f)
+            } else {
+                transitionAnimation.immediatelyTransitionTo(0f)
+            }
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt
index 8a3b57b..5741b94 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt
@@ -29,7 +29,6 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combineTransform
-import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.onStart
 
 /** Models UI state for the alpha of the AOD (always-on display). */
@@ -46,24 +45,23 @@
     /** The alpha level for the entire lockscreen while in AOD. */
     val alpha: Flow<Float> =
         combineTransform(
-                keyguardTransitionInteractor.transitions,
-                goneToAodTransitionViewModel.enterFromTopAnimationAlpha.onStart { emit(0f) },
-                goneToDozingTransitionViewModel.lockscreenAlpha.onStart { emit(0f) },
-                keyguardInteractor.keyguardAlpha.onStart { emit(1f) },
-            ) { step, goneToAodAlpha, goneToDozingAlpha, keyguardAlpha ->
-                if (step.to == GONE) {
-                    // When transitioning to GONE, only emit a value when complete as other
-                    // transitions may be controlling the alpha fade
-                    if (step.value == 1f) {
-                        emit(0f)
-                    }
-                } else if (step.from == GONE && step.to == AOD) {
-                    emit(goneToAodAlpha)
-                } else if (step.from == GONE && step.to == DOZING) {
-                    emit(goneToDozingAlpha)
-                } else if (!migrateClocksToBlueprint()) {
-                    emit(keyguardAlpha)
+            keyguardTransitionInteractor.transitions,
+            goneToAodTransitionViewModel.enterFromTopAnimationAlpha.onStart { emit(0f) },
+            goneToDozingTransitionViewModel.lockscreenAlpha.onStart { emit(0f) },
+            keyguardInteractor.keyguardAlpha.onStart { emit(1f) },
+        ) { step, goneToAodAlpha, goneToDozingAlpha, keyguardAlpha ->
+            if (step.to == GONE) {
+                // When transitioning to GONE, only emit a value when complete as other
+                // transitions may be controlling the alpha fade
+                if (step.value == 1f) {
+                    emit(0f)
                 }
+            } else if (step.from == GONE && step.to == AOD) {
+                emit(goneToAodAlpha)
+            } else if (step.from == GONE && step.to == DOZING) {
+                emit(goneToDozingAlpha)
+            } else if (!migrateClocksToBlueprint()) {
+                emit(keyguardAlpha)
             }
-            .distinctUntilChanged()
+        }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
index 8665aab..7be390a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
@@ -28,10 +28,6 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.shared.model.BurnInModel
-import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
-import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
-import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
-import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
 import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
@@ -47,7 +43,6 @@
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.onStart
 
 /**
@@ -127,17 +122,9 @@
         params: BurnInParameters,
     ): Flow<BurnInModel> {
         return combine(
-            merge(
-                    keyguardTransitionInteractor.transition(GONE, AOD).map { it.value },
-                    keyguardTransitionInteractor.transition(AOD, PRIMARY_BOUNCER).map {
-                        1f - it.value
-                    },
-                    keyguardTransitionInteractor.transition(ALTERNATE_BOUNCER, AOD).map {
-                        it.value
-                    },
-                    keyguardTransitionInteractor.dozeAmountTransition.map { it.value },
-                )
-                .map { dozeAmount -> Interpolators.FAST_OUT_SLOW_IN.getInterpolation(dozeAmount) },
+            keyguardTransitionInteractor.dozeAmountTransition.map {
+                Interpolators.FAST_OUT_SLOW_IN.getInterpolation(it.value)
+            },
             burnInInteractor.keyguardBurnIn,
         ) { interpolated, burnIn ->
             val useScaleOnly =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt
index b92a9a0..a9eec18 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt
@@ -16,13 +16,16 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import android.util.MathUtils
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.domain.interactor.FromAodTransitionInteractor
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
 import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
 import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
 
 /** Breaks down AOD->GONE transition into discrete steps for corresponding views to consume. */
 @ExperimentalCoroutinesApi
@@ -40,5 +43,15 @@
             to = KeyguardState.GONE,
         )
 
+    fun lockscreenAlpha(viewState: ViewStateAccessor): Flow<Float> {
+        var startAlpha = 1f
+        return transitionAnimation.sharedFlow(
+            duration = 200.milliseconds,
+            onStart = { startAlpha = viewState.alpha() },
+            onStep = { MathUtils.lerp(startAlpha, 0f, it) },
+            onFinish = { 0f },
+        )
+    }
+
     override val deviceEntryParentViewAlpha = transitionAnimation.immediatelyTransitionTo(0f)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
index 302ba72..662a77e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
@@ -46,6 +46,11 @@
     dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel,
     alternateBouncerToAodTransitionViewModel: AlternateBouncerToAodTransitionViewModel,
     goneToLockscreenTransitionViewModel: GoneToLockscreenTransitionViewModel,
+    goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel,
+    primaryBouncerToDozingTransitionViewModel: PrimaryBouncerToDozingTransitionViewModel,
+    lockscreenToDozingTransitionViewModel: LockscreenToDozingTransitionViewModel,
+    dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel,
+    alternateBouncerToDozingTransitionViewModel: AlternateBouncerToDozingTransitionViewModel,
 ) {
     val color: Flow<Int> =
         deviceEntryIconViewModel.useBackgroundProtection.flatMapLatest { useBackground ->
@@ -82,6 +87,11 @@
                         dreamingToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha,
                         alternateBouncerToAodTransitionViewModel.deviceEntryBackgroundViewAlpha,
                         goneToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha,
+                        goneToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
+                        primaryBouncerToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
+                        lockscreenToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
+                        dozingToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha,
+                        alternateBouncerToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
                     )
                     .merge()
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
index ad6a36c..6281097 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
@@ -33,6 +33,7 @@
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onStart
 
@@ -48,9 +49,9 @@
     deviceEntryIconViewModel: DeviceEntryIconViewModel,
     udfpsOverlayInteractor: UdfpsOverlayInteractor,
 ) {
-    private val isShowingAod: Flow<Boolean> =
+    private val isShowingAodOrDozing: Flow<Boolean> =
         transitionInteractor.startedKeyguardState.map { keyguardState ->
-            keyguardState == KeyguardState.AOD
+            keyguardState == KeyguardState.AOD || keyguardState == KeyguardState.DOZING
         }
 
     private fun getColor(usingBackgroundProtection: Boolean): Int {
@@ -68,13 +69,15 @@
                 .onStart { emit(getColor(useBgProtection)) }
         }
 
+    // While dozing, the display can show the AOD UI; show the AOD udfps when dozing
     private val useAodIconVariant: Flow<Boolean> =
-        combine(isShowingAod, deviceEntryUdfpsInteractor.isUdfpsSupported) {
-                isTransitionToAod,
-                isUdfps ->
-                isTransitionToAod && isUdfps
+        deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfspEnrolled ->
+            if (udfspEnrolled) {
+                isShowingAodOrDozing.distinctUntilChanged()
+            } else {
+                flowOf(false)
             }
-            .distinctUntilChanged()
+        }
 
     private val padding: Flow<Int> =
         deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { udfpsSupported ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index dc327ff..bd19c80 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -19,7 +19,6 @@
 import android.animation.FloatEvaluator
 import android.animation.IntEvaluator
 import com.android.keyguard.KeyguardViewController
-import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntrySourceInteractor
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
@@ -35,10 +34,12 @@
 import dagger.Lazy
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.merge
@@ -60,7 +61,6 @@
     private val keyguardViewController: Lazy<KeyguardViewController>,
     private val deviceEntryInteractor: DeviceEntryInteractor,
     private val deviceEntrySourceInteractor: DeviceEntrySourceInteractor,
-    private val fingerprintPropertyInteractor: FingerprintPropertyInteractor,
 ) {
     private val intEvaluator = IntEvaluator()
     private val floatEvaluator = FloatEvaluator()
@@ -179,20 +179,25 @@
             }
         }
 
-    /** Whether the device entry icon should be positioned at the location of UDFPS. */
-    val positionAtUdfpsLocation: Flow<Boolean> =
-        fingerprintPropertyInteractor.propertiesInitialized.flatMapLatest { initialized ->
-            if (initialized) {
-                fingerprintPropertyInteractor.isUdfps
+    private val isUnlocked: Flow<Boolean> =
+        keyguardInteractor.isKeyguardDismissible.flatMapLatest { isUnlocked ->
+            if (!isUnlocked) {
+                flowOf(false)
             } else {
-                // Don't update the position of the icon until properties are initialized.
-                emptyFlow()
+                flow {
+                    // delay in case device ends up transitioning away from the lock screen;
+                    // we don't want to animate to the unlocked icon and just let the
+                    // icon fade with the transition to GONE
+                    delay(UNLOCKED_DELAY_MS)
+                    emit(true)
+                }
             }
         }
+
     val iconType: Flow<DeviceEntryIconView.IconType> =
         combine(
             deviceEntryUdfpsInteractor.isListeningForUdfps,
-            keyguardInteractor.isKeyguardDismissible,
+            isUnlocked,
         ) { isListeningForUdfps, isUnlocked ->
             if (isListeningForUdfps) {
                 DeviceEntryIconView.IconType.FINGERPRINT
@@ -202,6 +207,7 @@
                 DeviceEntryIconView.IconType.LOCK
             }
         }
+    val isVisible: Flow<Boolean> = deviceEntryViewAlpha.map { it > 0f }.distinctUntilChanged()
     val isLongPressEnabled: Flow<Boolean> =
         combine(
             iconType,
@@ -213,6 +219,7 @@
                 DeviceEntryIconView.IconType.FINGERPRINT -> false
             }
         }
+
     val accessibilityDelegateHint: Flow<DeviceEntryIconView.AccessibilityHintType> =
         combine(iconType, isLongPressEnabled) { deviceEntryStatus, longPressEnabled ->
             if (longPressEnabled) {
@@ -241,6 +248,10 @@
                 DeviceEntryIconView.AccessibilityHintType.NONE
         }
     }
+
+    companion object {
+        const val UNLOCKED_DELAY_MS = 50L
+    }
 }
 
 data class BurnInOffsets(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModel.kt
new file mode 100644
index 0000000..8851a51
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModel.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import android.util.MathUtils
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromDozingTransitionInteractor.Companion.TO_GONE_DURATION
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+
+/** Breaks down DOZING->GONE transition into discrete steps for corresponding views to consume. */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class DozingToGoneTransitionViewModel
+@Inject
+constructor(
+    animationFlow: KeyguardTransitionAnimationFlow,
+) : DeviceEntryIconTransition {
+
+    private val transitionAnimation =
+        animationFlow.setup(
+            duration = TO_GONE_DURATION,
+            from = KeyguardState.DOZING,
+            to = KeyguardState.GONE,
+        )
+
+    fun lockscreenAlpha(viewState: ViewStateAccessor): Flow<Float> {
+        var startAlpha = 1f
+        return transitionAnimation.sharedFlow(
+            duration = 200.milliseconds,
+            onStart = { startAlpha = viewState.alpha() },
+            onStep = { MathUtils.lerp(startAlpha, 0f, it) },
+            onFinish = { 0f },
+        )
+    }
+
+    override val deviceEntryParentViewAlpha: Flow<Float> =
+        transitionAnimation.immediatelyTransitionTo(0f)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt
index f81941b..168d6e1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt
@@ -52,6 +52,9 @@
 
     val lockscreenAlpha: Flow<Float> = shortcutsAlpha
 
+    val deviceEntryBackgroundViewAlpha: Flow<Float> =
+        transitionAnimation.immediatelyTransitionTo(1f)
+
     override val deviceEntryParentViewAlpha: Flow<Float> =
         transitionAnimation.immediatelyTransitionTo(1f)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModel.kt
new file mode 100644
index 0000000..4395c34
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModel.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromDozingTransitionInteractor.Companion.TO_PRIMARY_BOUNCER_DURATION
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Breaks down DOZING->PRIMARY BOUNCER transition into discrete steps for corresponding views to
+ * consume.
+ */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class DozingToPrimaryBouncerTransitionViewModel
+@Inject
+constructor(
+    animationFlow: KeyguardTransitionAnimationFlow,
+) : DeviceEntryIconTransition {
+
+    private val transitionAnimation =
+        animationFlow.setup(
+            duration = TO_PRIMARY_BOUNCER_DURATION,
+            from = KeyguardState.DOZING,
+            to = KeyguardState.PRIMARY_BOUNCER,
+        )
+
+    override val deviceEntryParentViewAlpha: Flow<Float> =
+        transitionAnimation.immediatelyTransitionTo(0f)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
index 374a932..c64f277 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
@@ -17,18 +17,26 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import com.android.app.animation.Interpolators.EMPHASIZED
+import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.res.R
 import javax.inject.Inject
 import kotlin.time.Duration.Companion.milliseconds
 import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @SysUISingleton
 class DreamingToGlanceableHubTransitionViewModel
 @Inject
-constructor(animationFlow: KeyguardTransitionAnimationFlow) {
+constructor(
+    animationFlow: KeyguardTransitionAnimationFlow,
+    configurationInteractor: ConfigurationInteractor,
+) {
 
     private val transitionAnimation =
         animationFlow.setup(
@@ -37,14 +45,18 @@
             to = KeyguardState.GLANCEABLE_HUB,
         )
 
-    fun dreamOverlayTranslationX(translatePx: Int): Flow<Float> {
-        return transitionAnimation.sharedFlow(
-            duration = TO_GLANCEABLE_HUB_DURATION,
-            onStep = { it * -translatePx },
-            interpolator = EMPHASIZED,
-            name = "DREAMING->GLANCEABLE_HUB: overlayTranslationX",
-        )
-    }
+    val dreamOverlayTranslationX: Flow<Float> =
+        configurationInteractor
+            .dimensionPixelSize(R.dimen.dreaming_to_hub_transition_dream_overlay_translation_x)
+            .flatMapLatest { translatePx ->
+                transitionAnimation.sharedFlow(
+                    duration = TO_GLANCEABLE_HUB_DURATION,
+                    onStep = { value -> value * translatePx },
+                    interpolator = EMPHASIZED,
+                    onCancel = { 0f },
+                    name = "DREAMING->GLANCEABLE_HUB: overlayTranslationX",
+                )
+            }
 
     val dreamOverlayAlpha: Flow<Float> =
         transitionAnimation.sharedFlow(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
index 3802d5d..d3277cd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
@@ -18,7 +18,6 @@
 
 import com.android.app.animation.Interpolators.EMPHASIZED
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor
 import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -43,7 +42,6 @@
 constructor(
     keyguardTransitionInteractor: KeyguardTransitionInteractor,
     private val fromDreamingTransitionInteractor: FromDreamingTransitionInteractor,
-    private val deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
     animationFlow: KeyguardTransitionAnimationFlow,
 ) : DeviceEntryIconTransition {
     fun startTransition() = fromDreamingTransitionInteractor.startToLockscreenTransition()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt
new file mode 100644
index 0000000..478c4faa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import com.android.app.animation.Interpolators
+import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.res.R
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class GlanceableHubToDreamingTransitionViewModel
+@Inject
+constructor(
+    animationFlow: KeyguardTransitionAnimationFlow,
+    configurationInteractor: ConfigurationInteractor,
+) {
+
+    private val transitionAnimation =
+        animationFlow.setup(
+            duration = FROM_GLANCEABLE_HUB_DURATION,
+            from = KeyguardState.GLANCEABLE_HUB,
+            to = KeyguardState.DREAMING,
+        )
+
+    val dreamOverlayAlpha: Flow<Float> =
+        transitionAnimation.sharedFlow(
+            duration = 167.milliseconds,
+            startTime = 167.milliseconds,
+            onStep = { it },
+            name = "GLANCEABLE_HUB->DREAMING: dreamOverlayAlpha",
+        )
+
+    val dreamOverlayTranslationX: Flow<Float> =
+        configurationInteractor
+            .dimensionPixelSize(R.dimen.hub_to_dreaming_transition_dream_overlay_translation_x)
+            .flatMapLatest { translatePx: Int ->
+                transitionAnimation.sharedFlow(
+                    duration = FROM_GLANCEABLE_HUB_DURATION,
+                    onStep = { value -> -translatePx + value * translatePx },
+                    interpolator = Interpolators.EMPHASIZED,
+                    onCancel = { -translatePx.toFloat() },
+                    name = "GLANCEABLE_HUB->LOCKSCREEN: dreamOverlayTranslationX"
+                )
+            }
+
+    private companion object {
+        val FROM_GLANCEABLE_HUB_DURATION = 1.seconds
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt
index 55a289e..80a6bda 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt
@@ -17,13 +17,17 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_DOZING_DURATION
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
 import javax.inject.Inject
 import kotlin.time.Duration.Companion.milliseconds
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
 
 /** Breaks down GONE->DOZING transition into discrete steps for corresponding views to consume. */
 @ExperimentalCoroutinesApi
@@ -31,8 +35,9 @@
 class GoneToDozingTransitionViewModel
 @Inject
 constructor(
+    deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
     animationFlow: KeyguardTransitionAnimationFlow,
-) {
+) : DeviceEntryIconTransition {
 
     private val transitionAnimation =
         animationFlow.setup(
@@ -48,4 +53,17 @@
             onCancel = { 1f },
             onFinish = { 1f },
         )
+
+    val deviceEntryBackgroundViewAlpha: Flow<Float> =
+        transitionAnimation.immediatelyTransitionTo(0f)
+
+    override val deviceEntryParentViewAlpha: Flow<Float> =
+        deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest {
+            isUdfpsEnrolledAndEnabled ->
+            if (isUdfpsEnrolledAndEnabled) {
+                transitionAnimation.immediatelyTransitionTo(1f)
+            } else {
+                emptyFlow()
+            }
+        }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockViewModel.kt
index f95a8a7..b9ff259 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockViewModel.kt
@@ -45,9 +45,10 @@
     val isSmallClockVisible: Flow<Boolean> =
         interactor.selectedClockSize.map { it == SettingsClockSize.SMALL }
 
-    var lastClock: ClockController? = null
+    var lastClockPair: Pair<ClockController, ClockController>? = null
 
-    val previewClock: StateFlow<ClockController> = interactor.previewClock
+    val previewClockPair: StateFlow<Pair<ClockController, ClockController>> =
+        interactor.previewClockPair
 
     val selectedClockSize: StateFlow<SettingsClockSize?> =
         interactor.selectedClockSize.stateIn(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 921eb66..1760b92 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
 import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
 import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
+import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
 import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
 import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
 import com.android.systemui.keyguard.ui.StateToValue
@@ -70,10 +71,17 @@
     private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor,
     private val alternateBouncerToGoneTransitionViewModel:
         AlternateBouncerToGoneTransitionViewModel,
+    private val aodToGoneTransitionViewModel: AodToGoneTransitionViewModel,
     private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
+    private val dozingToGoneTransitionViewModel: DozingToGoneTransitionViewModel,
     private val dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel,
+    private val dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel,
     private val glanceableHubToLockscreenTransitionViewModel:
         GlanceableHubToLockscreenTransitionViewModel,
+    private val goneToAodTransitionViewModel: GoneToAodTransitionViewModel,
+    private val goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel,
+    private val lockscreenToAodTransitionViewModel: LockscreenToAodTransitionViewModel,
+    private val lockscreenToDozingTransitionViewModel: LockscreenToDozingTransitionViewModel,
     private val lockscreenToDreamingTransitionViewModel: LockscreenToDreamingTransitionViewModel,
     private val lockscreenToGlanceableHubTransitionViewModel:
         LockscreenToGlanceableHubTransitionViewModel,
@@ -116,6 +124,27 @@
             }
             .distinctUntilChanged()
 
+    /**
+     * Keyguard should not show while the communal hub is fully visible. This check is added since
+     * at the moment, closing the notification shade will cause the keyguard alpha to be set back to
+     * 1. Also ensure keyguard is never visible when GONE.
+     */
+    private val hideKeyguard: Flow<Boolean> =
+        combine(
+                communalInteractor.isIdleOnCommunal,
+                keyguardTransitionInteractor
+                    .transitionValue(GONE)
+                    .map { it == 1f }
+                    .onStart { emit(false) },
+                keyguardTransitionInteractor
+                    .transitionValue(OCCLUDED)
+                    .map { it == 1f }
+                    .onStart { emit(false) },
+            ) { isIdleOnCommunal, isGone, isOccluded ->
+                isIdleOnCommunal || isGone || isOccluded
+            }
+            .distinctUntilChanged()
+
     /** Last point that the root view was tapped */
     val lastRootViewTapPosition: Flow<Point?> = keyguardInteractor.lastRootViewTapPosition
 
@@ -132,18 +161,23 @@
     /** An observable for the alpha level for the entire keyguard root view. */
     fun alpha(viewState: ViewStateAccessor): Flow<Float> {
         return combine(
-                communalInteractor.isIdleOnCommunal,
-                keyguardTransitionInteractor.transitionValue(GONE).onStart { emit(0f) },
+                hideKeyguard,
                 // The transitions are mutually exclusive, so they are safe to merge to get the last
                 // value emitted by any of them. Do not add flows that cannot make this guarantee.
                 merge(
-                        aodAlphaViewModel.alpha,
                         alphaOnShadeExpansion,
                         keyguardInteractor.dismissAlpha.filterNotNull(),
                         alternateBouncerToGoneTransitionViewModel.lockscreenAlpha,
+                        aodToGoneTransitionViewModel.lockscreenAlpha(viewState),
                         aodToLockscreenTransitionViewModel.lockscreenAlpha(viewState),
+                        dozingToGoneTransitionViewModel.lockscreenAlpha(viewState),
                         dozingToLockscreenTransitionViewModel.lockscreenAlpha,
+                        dreamingToLockscreenTransitionViewModel.lockscreenAlpha,
                         glanceableHubToLockscreenTransitionViewModel.keyguardAlpha,
+                        goneToAodTransitionViewModel.enterFromTopAnimationAlpha,
+                        goneToDozingTransitionViewModel.lockscreenAlpha,
+                        lockscreenToAodTransitionViewModel.lockscreenAlpha(viewState),
+                        lockscreenToDozingTransitionViewModel.lockscreenAlpha,
                         lockscreenToDreamingTransitionViewModel.lockscreenAlpha,
                         lockscreenToGlanceableHubTransitionViewModel.keyguardAlpha,
                         lockscreenToGoneTransitionViewModel.lockscreenAlpha(viewState),
@@ -156,12 +190,8 @@
                         primaryBouncerToLockscreenTransitionViewModel.lockscreenAlpha,
                     )
                     .onStart { emit(1f) }
-            ) { isIdleOnCommunal, goneValue, alpha ->
-                if (isIdleOnCommunal || goneValue == 1f) {
-                    // Keyguard should not show while the communal hub is fully visible. This check
-                    // is added since at the moment, closing the notification shade will cause the
-                    // keyguard alpha to be set back to 1. Also ensure keyguard is never visible
-                    // when GONE.
+            ) { hideKeyguard, alpha ->
+                if (hideKeyguard) {
                     0f
                 } else {
                     alpha
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
index d792889..23320be 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
 import com.android.systemui.res.R
+import com.android.systemui.statusbar.policy.SplitShadeStateController
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.SharingStarted
@@ -39,6 +40,7 @@
     private val interactor: KeyguardBlueprintInteractor,
     private val authController: AuthController,
     val longPress: KeyguardLongPressViewModel,
+    val splitShadeStateController: SplitShadeStateController,
 ) {
     private val clockSize = clockInteractor.clockSize
 
@@ -46,8 +48,10 @@
         get() = authController.isUdfpsSupported
     val isLargeClockVisible: Boolean
         get() = clockSize.value == KeyguardClockSwitch.LARGE
-    val areNotificationsVisible: Boolean
-        get() = !isLargeClockVisible
+    fun areNotificationsVisible(resources: Resources): Boolean {
+        return !isLargeClockVisible ||
+            splitShadeStateController.shouldUseSplitNotificationShade(resources)
+    }
 
     fun getSmartSpacePaddingTop(resources: Resources): Int {
         return if (isLargeClockVisible) {
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 9afe8fc..b60e999 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
@@ -16,11 +16,12 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -51,13 +52,13 @@
             )
 
     private fun upDestinationSceneKey(isUnlocked: Boolean): SceneKey {
-        return if (isUnlocked) SceneKey.Gone else SceneKey.Bouncer
+        return if (isUnlocked) Scenes.Gone else Scenes.Bouncer
     }
 
     /** The key of the scene we should switch to when swiping left. */
     val leftDestinationSceneKey: StateFlow<SceneKey?> =
         communalInteractor.isCommunalAvailable
-            .map { available -> if (available) SceneKey.Communal else null }
+            .map { available -> if (available) Scenes.Communal else null }
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.WhileSubscribed(),
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt
index 7bf51a7..1f9f304 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import android.util.MathUtils
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor
@@ -67,6 +68,15 @@
             onCancel = { 1f },
         )
 
+    fun lockscreenAlpha(viewState: ViewStateAccessor): Flow<Float> {
+        var startAlpha = 1f
+        return transitionAnimation.sharedFlow(
+            duration = 500.milliseconds,
+            onStart = { startAlpha = viewState.alpha() },
+            onStep = { MathUtils.lerp(startAlpha, 1f, it) },
+        )
+    }
+
     override val deviceEntryParentViewAlpha: Flow<Float> =
         deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest {
             isUdfpsEnrolledAndEnabled ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt
index 4c0cd2f..c836f01 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt
@@ -17,19 +17,25 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_DOZING_DURATION
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
 import javax.inject.Inject
 import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @SysUISingleton
 class LockscreenToDozingTransitionViewModel
 @Inject
 constructor(
+    deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
     animationFlow: KeyguardTransitionAnimationFlow,
-) {
+) : DeviceEntryIconTransition {
 
     private val transitionAnimation =
         animationFlow.setup(
@@ -38,6 +44,14 @@
             to = KeyguardState.DOZING,
         )
 
+    val lockscreenAlpha: Flow<Float> =
+        transitionAnimation.sharedFlow(
+            duration = 250.milliseconds,
+            onStep = { 1 - it },
+            onFinish = { 1f },
+            onCancel = { 1f },
+        )
+
     val shortcutsAlpha: Flow<Float> =
         transitionAnimation.sharedFlow(
             duration = 250.milliseconds,
@@ -45,4 +59,19 @@
             onFinish = { 0f },
             onCancel = { 1f },
         )
+
+    val deviceEntryBackgroundViewAlpha: Flow<Float> =
+        transitionAnimation.immediatelyTransitionTo(0f)
+
+    override val deviceEntryParentViewAlpha: Flow<Float> =
+        deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest {
+            isUdfpsEnrolledAndEnabled ->
+            transitionAnimation.immediatelyTransitionTo(
+                if (isUdfpsEnrolledAndEnabled) {
+                    1f
+                } else {
+                    0f
+                }
+            )
+        }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/MediaCarouselViewModel.kt
similarity index 67%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/MediaCarouselViewModel.kt
index b370859..027a739 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/MediaCarouselViewModel.kt
@@ -16,12 +16,9 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
-import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.media.controls.domain.pipeline.MediaDataManager
+import javax.inject.Inject
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+class MediaCarouselViewModel @Inject constructor(mediaDataManager: MediaDataManager) {
+    val isMediaVisible: Boolean = mediaDataManager.hasActiveMediaOrRecommendation()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModel.kt
new file mode 100644
index 0000000..13f651a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModel.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_DOZING_DURATION
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+
+/**
+ * Breaks down PRIMARY BOUNCER->DOZING transition into discrete steps for corresponding views to
+ * consume.
+ */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class PrimaryBouncerToDozingTransitionViewModel
+@Inject
+constructor(
+    deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+    animationFlow: KeyguardTransitionAnimationFlow,
+) : DeviceEntryIconTransition {
+
+    private val transitionAnimation =
+        animationFlow.setup(
+            duration = TO_DOZING_DURATION,
+            from = KeyguardState.PRIMARY_BOUNCER,
+            to = KeyguardState.DOZING,
+        )
+
+    val deviceEntryBackgroundViewAlpha: Flow<Float> =
+        transitionAnimation.immediatelyTransitionTo(0f)
+
+    override val deviceEntryParentViewAlpha: Flow<Float> =
+        deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest {
+            isUdfpsEnrolledAndEnabled ->
+            if (isUdfpsEnrolledAndEnabled) {
+                transitionAnimation.immediatelyTransitionTo(1f)
+            } else {
+                emptyFlow()
+            }
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
index 378ce52..53f4488 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
@@ -60,6 +60,22 @@
     private var leaveShadeOpen: Boolean = false
     private var willRunDismissFromKeyguard: Boolean = false
 
+    val notificationAlpha: Flow<Float> =
+        transitionAnimation.sharedFlow(
+            duration = 200.milliseconds,
+            onStart = {
+                leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide()
+                willRunDismissFromKeyguard = primaryBouncerInteractor.willRunDismissFromKeyguard()
+            },
+            onStep = {
+                if (willRunDismissFromKeyguard || leaveShadeOpen) {
+                    1f
+                } else {
+                    1f - it
+                }
+            },
+        )
+
     /** Bouncer container alpha */
     val bouncerAlpha: Flow<Float> =
         if (featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
@@ -94,6 +110,7 @@
         } else {
             createLockscreenAlpha(primaryBouncerInteractor::willRunDismissFromKeyguard)
         }
+
     private fun createLockscreenAlpha(willRunAnimationOnKeyguard: () -> Boolean): Flow<Float> {
         return transitionAnimation.sharedFlow(
             duration = 50.milliseconds,
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 8b7c85b..f2013be 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -546,7 +546,7 @@
     @SysUISingleton
     @KeyguardLog
     public static LogBuffer provideKeyguardLogBuffer(LogBufferFactory factory) {
-        return factory.create("KeyguardLog", 250);
+        return factory.create("KeyguardLog", 500);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/media/OWNERS b/packages/SystemUI/src/com/android/systemui/media/OWNERS
index 69ea57b..5eb14fc 100644
--- a/packages/SystemUI/src/com/android/systemui/media/OWNERS
+++ b/packages/SystemUI/src/com/android/systemui/media/OWNERS
@@ -1 +1,9 @@
-per-file MediaProjectionPermissionActivity.java = michaelwr@google.com
+# Bug component: 78010
+
+asc@google.com
+ethibodeau@google.com
+michaelmikhil@google.com
+
+# Audio team
+per-file RingtonePlayer.java = file:/services/core/java/com/android/server/audio/OWNERS
+per-file NotificationPlayer.java = file:/services/core/java/com/android/server/audio/OWNERS
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt
index 6fc22ea..865c49e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.media.controls.domain.pipeline
 
 import android.annotation.SuppressLint
+import android.app.ActivityOptions
 import android.app.BroadcastOptions
 import android.app.Notification
 import android.app.Notification.EXTRA_SUBSTITUTE_APP_NAME
@@ -1272,7 +1273,7 @@
             val options = BroadcastOptions.makeBasic()
             options.setInteractive(true)
             options.setPendingIntentBackgroundActivityStartMode(
-                BroadcastOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+                ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
             )
             intent.send(options.toBundle())
             true
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
index 4e940f1..840b309 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
@@ -18,7 +18,7 @@
 
 import static android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS;
 
-import static com.android.systemui.Flags.legacyLeAudioSharing;
+import static com.android.settingslib.flags.Flags.legacyLeAudioSharing;
 import static com.android.systemui.media.controls.shared.model.SmartspaceMediaDataKt.NUM_REQUIRED_RECOMMENDATIONS;
 
 import android.animation.Animator;
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaControlsRefactorFlag.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaControlsRefactorFlag.kt
new file mode 100644
index 0000000..2850b4b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaControlsRefactorFlag.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.controls.util
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the media_controls_refactor flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object MediaControlsRefactorFlag {
+    /** The aconfig flag name */
+    const val FLAG_NAME = Flags.FLAG_MEDIA_CONTROLS_REFACTOR
+
+    /** A token used for dependency declaration */
+    val token: FlagToken
+        get() = FlagToken(FLAG_NAME, isEnabled)
+
+    /** Is the flag enabled? */
+    @JvmStatic
+    inline val isEnabled
+        get() = Flags.mediaControlsRefactor()
+
+    /**
+     * Called to ensure code is only run when the flag is enabled. This protects users from the
+     * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+     * build to ensure that the refactor author catches issues in testing.
+     */
+    @JvmStatic
+    inline fun isUnexpectedlyInLegacyMode() =
+        RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+    /**
+     * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+     * the flag is enabled to ensure that the refactor author catches issues in testing.
+     */
+    @JvmStatic
+    inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
index 15747b9..d4bd6da 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
@@ -58,4 +58,7 @@
     /** Check whether to use scene framework */
     fun isSceneContainerEnabled() =
         sceneContainerFlags.isEnabled() && MediaInSceneContainerFlag.isEnabled
+
+    /** Check whether to use media refactor code */
+    fun isMediaControlsRefactorEnabled() = MediaControlsRefactorFlag.isEnabled
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
index 8e0191e..1e31755 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.media.dialog;
 
+import static com.android.settingslib.flags.Flags.legacyLeAudioSharing;
+
 import android.app.AlertDialog;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothLeBroadcastAssistant;
@@ -492,6 +494,7 @@
 
     @Override
     public boolean isBroadcastSupported() {
+        if (!legacyLeAudioSharing()) return false;
         boolean isBluetoothLeDevice = false;
         if (mMediaOutputController.getCurrentConnectedMediaDevice() != null) {
             isBluetoothLeDevice = mMediaOutputController.isBluetoothLeDevice(
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index c379d0e..eb6a320 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.media.dialog;
 
-import static com.android.systemui.Flags.legacyLeAudioSharing;
+import static com.android.settingslib.flags.Flags.legacyLeAudioSharing;
 
 import android.content.Context;
 import android.os.Bundle;
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
index 1002cc3..38d31ed 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.media.dialog
 
+import com.android.settingslib.flags.Flags.legacyLeAudioSharing
 import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
@@ -44,6 +45,7 @@
                 mediaOutputDialogFactory.createDialogForSystemRouting()
             }
             MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG -> {
+                if (!legacyLeAudioSharing()) return
                 val packageName: String? =
                     intent.getStringExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME)
                 launchMediaOutputBroadcastDialogIfPossible(packageName)
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS b/packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS
new file mode 100644
index 0000000..95b8fa7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1280508
+
+# Files in this directory should still be reviewed by a member of SystemUI team
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt
index afe6285..0b19bab 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt
@@ -16,9 +16,6 @@
 
 package com.android.systemui.mediaprojection
 
-import android.compat.annotation.ChangeId
-import android.compat.annotation.Disabled
-import android.compat.annotation.Overridable
 import android.content.Context
 import android.media.projection.IMediaProjection
 import android.media.projection.IMediaProjectionManager
@@ -27,25 +24,15 @@
 import android.os.RemoteException
 import android.os.ServiceManager
 import android.util.Log
+import android.window.WindowContainerToken
+import javax.inject.Inject
 
 /**
  * Helper class that handles the media projection service related actions. It simplifies invoking
  * the MediaProjectionManagerService and updating the permission consent.
  */
-class MediaProjectionServiceHelper {
+class MediaProjectionServiceHelper @Inject constructor() {
     companion object {
-        /**
-         * This change id ensures that users are presented with a choice of capturing a single app
-         * or the entire screen when initiating a MediaProjection session, overriding the usage of
-         * MediaProjectionConfig#createConfigForDefaultDisplay.
-         *
-         * @hide
-         */
-        @ChangeId
-        @Overridable
-        @Disabled
-        const val OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION = 316897322L // buganizer id
-
         private const val TAG = "MediaProjectionServiceHelper"
         private val service =
             IMediaProjectionManager.Stub.asInterface(
@@ -105,4 +92,16 @@
             }
         }
     }
+
+    /** Updates the projected task to the task that has a matching [WindowContainerToken]. */
+    fun updateTaskRecordingSession(token: WindowContainerToken): Boolean {
+        return try {
+            true
+            // TODO: actually call the service once it is implemented
+            // service.updateTaskRecordingSession(token)
+        } catch (e: RemoteException) {
+            Log.e(TAG, "Unable to updateTaskRecordingSession", e)
+            false
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/OWNERS b/packages/SystemUI/src/com/android/systemui/mediaprojection/OWNERS
new file mode 100644
index 0000000..bd74077
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 1345447
+
+include /media/java/android/media/projection/OWNERS
+chrisgollner@google.com
+nickchameyev@google.com
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 a811065..7c7efd0 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
@@ -18,7 +18,7 @@
 
 import android.app.ActivityOptions
 import android.app.ActivityOptions.LaunchCookie
-import android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+import android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
 import android.app.IActivityTaskManager
 import android.graphics.Rect
 import android.view.LayoutInflater
@@ -26,12 +26,13 @@
 import android.view.ViewGroup
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
-import com.android.systemui.res.R
+import com.android.systemui.Flags.pssAppSelectorAbruptExitFix
 import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorResultHandler
 import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorScope
 import com.android.systemui.mediaprojection.appselector.data.RecentTask
 import com.android.systemui.mediaprojection.appselector.view.RecentTasksAdapter.RecentTaskClickListener
 import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider.TaskPreviewSizeListener
+import com.android.systemui.res.R
 import com.android.systemui.util.recycler.HorizontalSpacerItemDecoration
 import javax.inject.Inject
 
@@ -122,14 +123,7 @@
 
     override fun onRecentAppClicked(task: RecentTask, view: View) {
         val launchCookie = LaunchCookie()
-        val activityOptions =
-            ActivityOptions.makeScaleUpAnimation(
-                view,
-                /* startX= */ 0,
-                /* startY= */ 0,
-                view.width,
-                view.height
-            )
+        val activityOptions = createAnimation(task, view)
         activityOptions.pendingIntentBackgroundActivityStartMode =
             MODE_BACKGROUND_ACTIVITY_START_ALLOWED
         activityOptions.setLaunchCookie(launchCookie)
@@ -139,6 +133,28 @@
         resultHandler.returnSelectedApp(launchCookie)
     }
 
+    private fun createAnimation(task: RecentTask, view: View): ActivityOptions =
+        if (pssAppSelectorAbruptExitFix() && task.isForegroundTask) {
+            // When the selected task is in the foreground, the scale up animation doesn't work.
+            // We fallback to the default close animation.
+            ActivityOptions.makeCustomTaskAnimation(
+                view.context,
+                /* enterResId= */ 0,
+                /* exitResId= */ com.android.internal.R.anim.resolver_close_anim,
+                /* handler = */ null,
+                /* startedListener = */ null,
+                /* finishedListener = */ null
+            )
+        } else {
+            ActivityOptions.makeScaleUpAnimation(
+                view,
+                /* startX= */ 0,
+                /* startY= */ 0,
+                view.width,
+                view.height
+            )
+        }
+
     override fun onTaskSizeChanged(size: Rect) {
         views?.recentsContainer?.setTaskHeightSize()
     }
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index 0769731..8b034b2 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -16,26 +16,21 @@
 
 package com.android.systemui.mediaprojection.permission;
 
-import static android.Manifest.permission.LOG_COMPAT_CHANGE;
-import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
 import static android.media.projection.IMediaProjectionManager.EXTRA_PACKAGE_REUSING_GRANTED_CONSENT;
 import static android.media.projection.IMediaProjectionManager.EXTRA_USER_REVIEW_GRANTED_CONSENT;
 import static android.media.projection.ReviewGrantedConsentResult.RECORD_CANCEL;
 import static android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
 
-import static com.android.systemui.mediaprojection.MediaProjectionServiceHelper.OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION;
 import static com.android.systemui.mediaprojection.permission.ScreenShareOptionKt.ENTIRE_SCREEN;
 import static com.android.systemui.mediaprojection.permission.ScreenShareOptionKt.SINGLE_APP;
 
 import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityOptions.LaunchCookie;
 import android.app.AlertDialog;
 import android.app.StatusBarManager;
-import android.app.compat.CompatChanges;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -109,7 +104,6 @@
     }
 
     @Override
-    @RequiresPermission(allOf = {READ_COMPAT_CHANGE_CONFIG, LOG_COMPAT_CHANGE})
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
@@ -237,9 +231,6 @@
         // the correct screen width when in split screen.
         Context dialogContext = getApplicationContext();
         if (isPartialScreenSharingEnabled()) {
-            final boolean overrideDisableSingleAppOption = CompatChanges.isChangeEnabled(
-                    OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION,
-                    mPackageName, getHostUserHandle());
             MediaProjectionPermissionDialogDelegate delegate =
                     new MediaProjectionPermissionDialogDelegate(
                             dialogContext,
@@ -251,7 +242,6 @@
                             },
                             () -> finish(RECORD_CANCEL, /* projection= */ null),
                             appName,
-                            overrideDisableSingleAppOption,
                             mUid,
                             mMediaProjectionMetricsLogger);
             mDialog =
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt
index 9ce8070..0f54e93 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt
@@ -30,12 +30,11 @@
     private val onStartRecordingClicked: Consumer<MediaProjectionPermissionDialogDelegate>,
     private val onCancelClicked: Runnable,
     private val appName: String?,
-    forceShowPartialScreenshare: Boolean,
     hostUid: Int,
     mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
 ) :
     BaseMediaProjectionPermissionDialogDelegate<AlertDialog>(
-        createOptionList(context, appName, mediaProjectionConfig, forceShowPartialScreenshare),
+        createOptionList(context, appName, mediaProjectionConfig),
         appName,
         hostUid,
         mediaProjectionMetricsLogger
@@ -66,8 +65,7 @@
         private fun createOptionList(
             context: Context,
             appName: String?,
-            mediaProjectionConfig: MediaProjectionConfig?,
-            overrideDisableSingleAppOption: Boolean = false,
+            mediaProjectionConfig: MediaProjectionConfig?
         ): List<ScreenShareOption> {
             val singleAppWarningText =
                 if (appName == null) {
@@ -82,13 +80,8 @@
                     R.string.media_projection_entry_app_permission_dialog_warning_entire_screen
                 }
 
-            // The single app option should only be disabled if there is an app name provided,
-            // the client has setup a MediaProjection with
-            // MediaProjectionConfig#createConfigForDefaultDisplay, AND it hasn't been overridden by
-            // the OVERRIDE_DISABLE_SINGLE_APP_OPTION per-app override.
             val singleAppOptionDisabled =
                 appName != null &&
-                    !overrideDisableSingleAppOption &&
                     mediaProjectionConfig?.regionToCapture ==
                         MediaProjectionConfig.CAPTURE_REGION_FIXED_DISPLAY
 
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/model/MediaProjectionState.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/model/MediaProjectionState.kt
index 9938f11..cfbcaf9 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/model/MediaProjectionState.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/model/MediaProjectionState.kt
@@ -16,11 +16,11 @@
 
 package com.android.systemui.mediaprojection.taskswitcher.data.model
 
-import android.app.TaskInfo
+import android.app.ActivityManager.RunningTaskInfo
 
 /** Represents the state of media projection. */
 sealed interface MediaProjectionState {
     object NotProjecting : MediaProjectionState
     object EntireScreen : MediaProjectionState
-    data class SingleTask(val task: TaskInfo) : MediaProjectionState
+    data class SingleTask(val task: RunningTaskInfo) : MediaProjectionState
 }
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepository.kt
index 492d482..4ff54d4e 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepository.kt
@@ -17,10 +17,14 @@
 package com.android.systemui.mediaprojection.taskswitcher.data.repository
 
 import android.app.ActivityManager.RunningTaskInfo
+import android.app.ActivityOptions
+import android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
 import android.app.ActivityTaskManager
+import android.app.IActivityTaskManager
 import android.app.TaskStackListener
 import android.os.IBinder
 import android.util.Log
+import android.view.Display
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
@@ -40,11 +44,24 @@
 class ActivityTaskManagerTasksRepository
 @Inject
 constructor(
-    private val activityTaskManager: ActivityTaskManager,
+    private val activityTaskManager: IActivityTaskManager,
     @Application private val applicationScope: CoroutineScope,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
 ) : TasksRepository {
 
+    override suspend fun launchRecentTask(taskInfo: RunningTaskInfo) {
+        withContext(backgroundDispatcher) {
+            val activityOptions = ActivityOptions.makeBasic()
+            activityOptions.pendingIntentBackgroundActivityStartMode =
+                MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+            activityOptions.launchDisplayId = taskInfo.displayId
+            activityTaskManager.startActivityFromRecents(
+                taskInfo.taskId,
+                activityOptions.toBundle()
+            )
+        }
+    }
+
     override suspend fun findRunningTaskFromWindowContainerToken(
         windowContainerToken: IBinder
     ): RunningTaskInfo? =
@@ -53,7 +70,14 @@
         }
 
     private suspend fun getRunningTasks(): List<RunningTaskInfo> =
-        withContext(backgroundDispatcher) { activityTaskManager.getTasks(Integer.MAX_VALUE) }
+        withContext(backgroundDispatcher) {
+            activityTaskManager.getTasks(
+                /* maxNum = */ Integer.MAX_VALUE,
+                /* filterForVisibleRecents = */ false,
+                /* keepIntentExtra = */ false,
+                /* displayId = */ Display.INVALID_DISPLAY
+            )
+        }
 
     override val foregroundTask: Flow<RunningTaskInfo> =
         conflatedCallbackFlow {
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepository.kt
index 6480a47..74d1992 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepository.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.mediaprojection.taskswitcher.data.repository
 
+import android.app.ActivityManager.RunningTaskInfo
 import android.media.projection.MediaProjectionInfo
 import android.media.projection.MediaProjectionManager
 import android.os.Handler
@@ -26,15 +27,19 @@
 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.dagger.qualifiers.Main
+import com.android.systemui.mediaprojection.MediaProjectionServiceHelper
 import com.android.systemui.mediaprojection.taskswitcher.data.model.MediaProjectionState
 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.SharingStarted
 import kotlinx.coroutines.flow.shareIn
 import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
 
 @SysUISingleton
 class MediaProjectionManagerRepository
@@ -43,9 +48,21 @@
     private val mediaProjectionManager: MediaProjectionManager,
     @Main private val handler: Handler,
     @Application private val applicationScope: CoroutineScope,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
     private val tasksRepository: TasksRepository,
+    private val mediaProjectionServiceHelper: MediaProjectionServiceHelper,
 ) : MediaProjectionRepository {
 
+    override suspend fun switchProjectedTask(task: RunningTaskInfo) {
+        withContext(backgroundDispatcher) {
+            if (mediaProjectionServiceHelper.updateTaskRecordingSession(task.token)) {
+                Log.d(TAG, "Successfully switched projected task")
+            } else {
+                Log.d(TAG, "Failed to switch projected task")
+            }
+        }
+    }
+
     override val mediaProjectionState: Flow<MediaProjectionState> =
         conflatedCallbackFlow {
                 val callback =
@@ -82,7 +99,9 @@
         }
         val matchingTask =
             tasksRepository.findRunningTaskFromWindowContainerToken(
-                checkNotNull(session.tokenToRecord)) ?: return MediaProjectionState.EntireScreen
+                checkNotNull(session.tokenToRecord)
+            )
+                ?: return MediaProjectionState.EntireScreen
         return MediaProjectionState.SingleTask(matchingTask)
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionRepository.kt
index 5bec692..e495466 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionRepository.kt
@@ -16,12 +16,16 @@
 
 package com.android.systemui.mediaprojection.taskswitcher.data.repository
 
+import android.app.ActivityManager.RunningTaskInfo
 import com.android.systemui.mediaprojection.taskswitcher.data.model.MediaProjectionState
 import kotlinx.coroutines.flow.Flow
 
 /** Represents a repository to retrieve and change data related to media projection. */
 interface MediaProjectionRepository {
 
+    /** Switches the task that should be projected. */
+    suspend fun switchProjectedTask(task: RunningTaskInfo)
+
     /** Represents the current [MediaProjectionState]. */
     val mediaProjectionState: Flow<MediaProjectionState>
 }
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/NoOpMediaProjectionRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/NoOpMediaProjectionRepository.kt
deleted file mode 100644
index 544eb6b..0000000
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/NoOpMediaProjectionRepository.kt
+++ /dev/null
@@ -1,33 +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.mediaprojection.taskswitcher.data.repository
-
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.mediaprojection.taskswitcher.data.model.MediaProjectionState
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.emptyFlow
-
-/**
- * No-op implementation of [MediaProjectionRepository] that does nothing. Currently used as a
- * placeholder, while the real implementation is not completed.
- */
-@SysUISingleton
-class NoOpMediaProjectionRepository @Inject constructor() : MediaProjectionRepository {
-
-    override val mediaProjectionState: Flow<MediaProjectionState> = emptyFlow()
-}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/TasksRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/TasksRepository.kt
index 6a535e4..9ef42b4 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/TasksRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/TasksRepository.kt
@@ -23,6 +23,8 @@
 /** Repository responsible for retrieving data related to running tasks. */
 interface TasksRepository {
 
+    suspend fun launchRecentTask(taskInfo: RunningTaskInfo)
+
     /**
      * Tries to find a [RunningTaskInfo] with a matching window container token. Returns `null` when
      * no matching task was found.
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt
index fc5cf7d..eb9e6a5 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.mediaprojection.taskswitcher.domain.interactor
 
+import android.app.ActivityManager.RunningTaskInfo
 import android.app.TaskInfo
 import android.content.Intent
 import android.util.Log
@@ -37,10 +38,18 @@
 class TaskSwitchInteractor
 @Inject
 constructor(
-    mediaProjectionRepository: MediaProjectionRepository,
+    private val mediaProjectionRepository: MediaProjectionRepository,
     private val tasksRepository: TasksRepository,
 ) {
 
+    suspend fun switchProjectedTask(task: RunningTaskInfo) {
+        mediaProjectionRepository.switchProjectedTask(task)
+    }
+
+    suspend fun goBackToTask(task: RunningTaskInfo) {
+        tasksRepository.launchRecentTask(task)
+    }
+
     /**
      * Emits a stream of changes to the state of task switching, in the context of media projection.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/model/TaskSwitchState.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/model/TaskSwitchState.kt
index cd1258e..caabc64 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/model/TaskSwitchState.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/model/TaskSwitchState.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.mediaprojection.taskswitcher.domain.model
 
-import android.app.TaskInfo
+import android.app.ActivityManager.RunningTaskInfo
 
 /** Represents tha state of task switching in the context of single task media projection. */
 sealed interface TaskSwitchState {
@@ -25,6 +25,8 @@
     /** The foreground task is the same as the task that is currently being projected. */
     object TaskUnchanged : TaskSwitchState
     /** The foreground task is a different one to the task it currently being projected. */
-    data class TaskSwitched(val projectedTask: TaskInfo, val foregroundTask: TaskInfo) :
-        TaskSwitchState
+    data class TaskSwitched(
+        val projectedTask: RunningTaskInfo,
+        val foregroundTask: RunningTaskInfo
+    ) : TaskSwitchState
 }
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinator.kt
index 7840da9..dab7439 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinator.kt
@@ -16,23 +16,25 @@
 
 package com.android.systemui.mediaprojection.taskswitcher.ui
 
+import android.app.ActivityManager.RunningTaskInfo
 import android.app.Notification
-import android.app.NotificationChannel
 import android.app.NotificationManager
+import android.app.PendingIntent
 import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.Parcelable
 import android.util.Log
-import com.android.systemui.res.R
+import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.mediaprojection.taskswitcher.ui.model.TaskSwitcherNotificationUiState.NotShowing
 import com.android.systemui.mediaprojection.taskswitcher.ui.model.TaskSwitcherNotificationUiState.Showing
 import com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel.TaskSwitcherNotificationViewModel
+import com.android.systemui.res.R
 import com.android.systemui.util.NotificationChannels
 import javax.inject.Inject
-import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.launch
 
 /** Coordinator responsible for showing/hiding the task switcher notification. */
@@ -43,32 +45,54 @@
     private val context: Context,
     private val notificationManager: NotificationManager,
     @Application private val applicationScope: CoroutineScope,
-    @Main private val mainDispatcher: CoroutineDispatcher,
     private val viewModel: TaskSwitcherNotificationViewModel,
+    private val broadcastDispatcher: BroadcastDispatcher,
 ) {
+
     fun start() {
         applicationScope.launch {
-            viewModel.uiState.flowOn(mainDispatcher).collect { uiState ->
-                Log.d(TAG, "uiState -> $uiState")
-                when (uiState) {
-                    is Showing -> showNotification()
-                    is NotShowing -> hideNotification()
+            launch {
+                viewModel.uiState.collect { uiState ->
+                    Log.d(TAG, "uiState -> $uiState")
+                    when (uiState) {
+                        is Showing -> showNotification(uiState)
+                        is NotShowing -> hideNotification()
+                    }
                 }
             }
+            launch {
+                broadcastDispatcher
+                    .broadcastFlow(IntentFilter(SWITCH_ACTION)) { intent, _ ->
+                        intent.requireParcelableExtra<RunningTaskInfo>(EXTRA_ACTION_TASK)
+                    }
+                    .collect { task: RunningTaskInfo ->
+                        Log.d(TAG, "Switch action triggered: $task")
+                        viewModel.onSwitchTaskClicked(task)
+                    }
+            }
+            launch {
+                broadcastDispatcher
+                    .broadcastFlow(IntentFilter(GO_BACK_ACTION)) { intent, _ ->
+                        intent.requireParcelableExtra<RunningTaskInfo>(EXTRA_ACTION_TASK)
+                    }
+                    .collect { task ->
+                        Log.d(TAG, "Go back action triggered: $task")
+                        viewModel.onGoBackToTaskClicked(task)
+                    }
+            }
         }
     }
 
-    private fun showNotification() {
-        notificationManager.notify(TAG, NOTIFICATION_ID, createNotification())
+    private fun showNotification(uiState: Showing) {
+        notificationManager.notify(TAG, NOTIFICATION_ID, createNotification(uiState))
     }
 
-    private fun createNotification(): Notification {
-        // TODO(b/286201261): implement actions
+    private fun createNotification(uiState: Showing): Notification {
         val actionSwitch =
             Notification.Action.Builder(
                     /* icon = */ null,
                     context.getString(R.string.media_projection_task_switcher_action_switch),
-                    /* intent = */ null
+                    createActionPendingIntent(action = SWITCH_ACTION, task = uiState.foregroundTask)
                 )
                 .build()
 
@@ -76,34 +100,40 @@
             Notification.Action.Builder(
                     /* icon = */ null,
                     context.getString(R.string.media_projection_task_switcher_action_back),
-                    /* intent = */ null
+                    createActionPendingIntent(action = GO_BACK_ACTION, task = uiState.projectedTask)
                 )
                 .build()
-
-        val channel =
-            NotificationChannel(
-                NotificationChannels.HINTS,
-                context.getString(R.string.media_projection_task_switcher_notification_channel),
-                NotificationManager.IMPORTANCE_HIGH
-            )
-        notificationManager.createNotificationChannel(channel)
-        return Notification.Builder(context, channel.id)
+        return Notification.Builder(context, NotificationChannels.ALERTS)
             .setSmallIcon(R.drawable.qs_screen_record_icon_on)
             .setAutoCancel(true)
             .setContentText(context.getString(R.string.media_projection_task_switcher_text))
             .addAction(actionSwitch)
             .addAction(actionBack)
-            .setPriority(Notification.PRIORITY_HIGH)
-            .setDefaults(Notification.DEFAULT_VIBRATE)
             .build()
     }
 
     private fun hideNotification() {
-        notificationManager.cancel(NOTIFICATION_ID)
+        notificationManager.cancel(TAG, NOTIFICATION_ID)
     }
 
+    private fun createActionPendingIntent(action: String, task: RunningTaskInfo) =
+        PendingIntent.getBroadcast(
+            context,
+            /* requestCode= */ 0,
+            Intent(action).apply { putExtra(EXTRA_ACTION_TASK, task) },
+            /* flags= */ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
+        )
+
     companion object {
         private const val TAG = "TaskSwitchNotifCoord"
         private const val NOTIFICATION_ID = 5566
+
+        private const val EXTRA_ACTION_TASK = "extra_task"
+
+        private const val SWITCH_ACTION = "com.android.systemui.mediaprojection.SWITCH_TASK"
+        private const val GO_BACK_ACTION = "com.android.systemui.mediaprojection.GO_BACK"
     }
 }
+
+private fun <T : Parcelable> Intent.requireParcelableExtra(key: String) =
+    getParcelableExtra<T>(key)!!
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/model/TaskSwitcherNotificationUiState.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/model/TaskSwitcherNotificationUiState.kt
index 21aee72..f307761 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/model/TaskSwitcherNotificationUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/model/TaskSwitcherNotificationUiState.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.mediaprojection.taskswitcher.ui.model
 
-import android.app.TaskInfo
+import android.app.ActivityManager.RunningTaskInfo
 
 /** Represents the UI state for the task switcher notification. */
 sealed interface TaskSwitcherNotificationUiState {
@@ -24,7 +24,7 @@
     object NotShowing : TaskSwitcherNotificationUiState
     /** The notification should be shown. */
     data class Showing(
-        val projectedTask: TaskInfo,
-        val foregroundTask: TaskInfo,
+        val projectedTask: RunningTaskInfo,
+        val foregroundTask: RunningTaskInfo,
     ) : TaskSwitcherNotificationUiState
 }
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModel.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModel.kt
index d9754d4..cc8cc51 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModel.kt
@@ -16,15 +16,24 @@
 
 package com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel
 
+import android.app.ActivityManager.RunningTaskInfo
 import android.util.Log
+import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.mediaprojection.taskswitcher.domain.interactor.TaskSwitchInteractor
 import com.android.systemui.mediaprojection.taskswitcher.domain.model.TaskSwitchState
 import com.android.systemui.mediaprojection.taskswitcher.ui.model.TaskSwitcherNotificationUiState
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.withContext
 
-class TaskSwitcherNotificationViewModel @Inject constructor(interactor: TaskSwitchInteractor) {
+class TaskSwitcherNotificationViewModel
+@Inject
+constructor(
+    private val interactor: TaskSwitchInteractor,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
+) {
 
     val uiState: Flow<TaskSwitcherNotificationUiState> =
         interactor.taskSwitchChanges.map { taskSwitchChange ->
@@ -43,6 +52,13 @@
             }
         }
 
+    suspend fun onSwitchTaskClicked(task: RunningTaskInfo) {
+        interactor.switchProjectedTask(task)
+    }
+
+    suspend fun onGoBackToTaskClicked(task: RunningTaskInfo) =
+        withContext(backgroundDispatcher) { interactor.goBackToTask(task) }
+
     companion object {
         private const val TAG = "TaskSwitchNotifVM"
     }
diff --git a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
index 6eb6226..e7b6e63 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
+++ b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
@@ -16,11 +16,12 @@
 
 package com.android.systemui.model
 
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE
@@ -67,11 +68,11 @@
          */
         val EvaluatorByFlag =
             mapOf<Int, (SceneKey) -> Boolean>(
-                SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE to { it != SceneKey.Gone },
-                SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED to { it == SceneKey.Shade },
-                SYSUI_STATE_QUICK_SETTINGS_EXPANDED to { it == SceneKey.QuickSettings },
-                SYSUI_STATE_BOUNCER_SHOWING to { it == SceneKey.Bouncer },
-                SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to { it == SceneKey.Lockscreen },
+                SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE to { it != Scenes.Gone },
+                SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED to { it == Scenes.Shade },
+                SYSUI_STATE_QUICK_SETTINGS_EXPANDED to { it == Scenes.QuickSettings },
+                SYSUI_STATE_BOUNCER_SHOWING to { it == Scenes.Bouncer },
+                SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to { it == Scenes.Lockscreen },
             )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUiStateExt.kt b/packages/SystemUI/src/com/android/systemui/model/SysUiStateExt.kt
index c74a71c..5c49156 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SysUiStateExt.kt
+++ b/packages/SystemUI/src/com/android/systemui/model/SysUiStateExt.kt
@@ -25,11 +25,11 @@
  * ```
  * sysuiState.updateFlags(
  *     displayId,
- *     SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE to (sceneKey != SceneKey.Gone),
- *     SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED to (sceneKey == SceneKey.Shade),
- *     SYSUI_STATE_QUICK_SETTINGS_EXPANDED to (sceneKey == SceneKey.QuickSettings),
- *     SYSUI_STATE_BOUNCER_SHOWING to (sceneKey == SceneKey.Bouncer),
- *     SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to (sceneKey == SceneKey.Lockscreen),
+ *     SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE to (sceneKey != Scenes.Gone),
+ *     SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED to (sceneKey == Scenes.Shade),
+ *     SYSUI_STATE_QUICK_SETTINGS_EXPANDED to (sceneKey == Scenes.QuickSettings),
+ *     SYSUI_STATE_BOUNCER_SHOWING to (sceneKey == Scenes.Bouncer),
+ *     SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to (sceneKey == Scenes.Lockscreen),
  * )
  * ```
  *
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index aa03e6e..5dd1bd8 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -495,10 +495,6 @@
         return mBehavior != BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
     }
 
-    private boolean isImmersiveMode() {
-        return mBehavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
-    }
-
     public void onConfigurationChanged(Configuration configuration) {
         mEdgeBackGestureHandler.onConfigurationChanged(configuration);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.kt b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.kt
index 5b7eb45..deb0fed 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.kt
@@ -20,14 +20,15 @@
 import android.os.Bundle
 import android.util.Log
 import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.compose.ComposeFacade.isComposeAvailable
-import com.android.systemui.compose.ComposeFacade.setPeopleSpaceActivityContent
+import com.android.compose.theme.PlatformTheme
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.people.ui.compose.PeopleScreen
 import com.android.systemui.people.ui.view.PeopleViewBinder
 import com.android.systemui.people.ui.view.PeopleViewBinder.bind
 import com.android.systemui.people.ui.viewmodel.PeopleViewModel
@@ -65,13 +66,11 @@
         }
 
         // Set the content of the activity, using either the View or Compose implementation.
-        if (featureFlags.isEnabled(Flags.COMPOSE_PEOPLE_SPACE) && isComposeAvailable()) {
+        if (featureFlags.isEnabled(Flags.COMPOSE_PEOPLE_SPACE)) {
             Log.d(TAG, "Using the Compose implementation of the PeopleSpaceActivity")
-            setPeopleSpaceActivityContent(
-                activity = this,
-                viewModel,
-                onResult = { finishActivity(it) },
-            )
+            setContent {
+                PlatformTheme { PeopleScreen(viewModel, onResult = { finishActivity(it) }) }
+            }
         } else {
             Log.d(TAG, "Using the View implementation of the PeopleSpaceActivity")
             val view = PeopleViewBinder.create(this)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
index 7413362..a000d63 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
@@ -47,7 +47,6 @@
 import com.android.keyguard.BouncerPanelExpansionCalculator;
 import com.android.systemui.Dumpable;
 import com.android.systemui.animation.ShadeInterpolation;
-import com.android.systemui.compose.ComposeFacade;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
@@ -301,8 +300,7 @@
     private void bindFooterActionsView(View root) {
         LinearLayout footerActionsView = root.findViewById(R.id.qs_footer_actions);
 
-        if (!mFeatureFlags.isEnabled(Flags.COMPOSE_QS_FOOTER_ACTIONS)
-                || !ComposeFacade.INSTANCE.isComposeAvailable()) {
+        if (!mFeatureFlags.isEnabled(Flags.COMPOSE_QS_FOOTER_ACTIONS)) {
             Log.d(TAG, "Binding the View implementation of the QS footer actions");
             mFooterActionsView = footerActionsView;
             mFooterActionsViewBinder.bind(footerActionsView, mQSFooterActionsViewModel,
@@ -312,7 +310,7 @@
 
         // Compose is available, so let's use the Compose implementation of the footer actions.
         Log.d(TAG, "Binding the Compose implementation of the QS footer actions");
-        View composeView = ComposeFacade.INSTANCE.createFooterActionsView(root.getContext(),
+        View composeView = QSUtils.createFooterActionsView(root.getContext(),
                 mQSFooterActionsViewModel, mListeningAndVisibilityLifecycleOwner);
         mFooterActionsView = composeView;
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSUtils.kt b/packages/SystemUI/src/com/android/systemui/qs/QSUtils.kt
index e42264f24..15c3f27 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSUtils.kt
@@ -1,7 +1,13 @@
 package com.android.systemui.qs
 
 import android.content.Context
+import android.view.View
+import androidx.lifecycle.LifecycleOwner
+import com.android.compose.theme.PlatformTheme
+import com.android.compose.ui.platform.DensityAwareComposeView
 import com.android.internal.policy.SystemBarUtils
+import com.android.systemui.qs.footer.ui.compose.FooterActions
+import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
 import com.android.systemui.util.LargeScreenUtils.shouldUseLargeScreenShadeHeader
 
 object QSUtils {
@@ -21,4 +27,15 @@
             SystemBarUtils.getQuickQsOffsetHeight(context)
         }
     }
-}
\ No newline at end of file
+
+    @JvmStatic
+    fun createFooterActionsView(
+        context: Context,
+        viewModel: FooterActionsViewModel,
+        qsVisibilityLifecycleOwner: LifecycleOwner,
+    ): View {
+        return DensityAwareComposeView(context).apply {
+            setContent { PlatformTheme { FooterActions(viewModel, qsVisibilityLifecycleOwner) } }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt
index 168fa08..15b8cfb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SubtitleArrayMapping.kt
@@ -39,6 +39,7 @@
         subtitleIdsMap["cast"] = R.array.tile_states_cast
         subtitleIdsMap["night"] = R.array.tile_states_night
         subtitleIdsMap["screenrecord"] = R.array.tile_states_screenrecord
+        subtitleIdsMap["record_issue"] = R.array.tile_states_record_issue
         subtitleIdsMap["reverse"] = R.array.tile_states_reverse
         subtitleIdsMap["reduce_brightness"] = R.array.tile_states_reduce_brightness
         subtitleIdsMap["cameratoggle"] = R.array.tile_states_cameratoggle
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
index b1e2467..20f3c4d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
@@ -85,7 +85,13 @@
 
     override fun getTileLabel(): CharSequence = mContext.getString(R.string.qs_record_issue_label)
 
-    override fun isAvailable(): Boolean = recordIssueQsTile()
+    /**
+     * There are SELinux constraints that are stopping this tile from reaching production builds.
+     * Once those are resolved, this condition will be removed, but the solution (of properly
+     * creating a distince SELinux context for com.android.systemui) is complex and will take time
+     * to implement.
+     */
+    override fun isAvailable(): Boolean = android.os.Build.IS_DEBUGGABLE && recordIssueQsTile()
 
     override fun newTileState(): QSTile.BooleanState =
         QSTile.BooleanState().apply {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegate.kt
similarity index 67%
rename from packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
rename to packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegate.kt
index 6b53c7a..7ece6e0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegate.kt
@@ -37,11 +37,13 @@
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import com.android.internal.logging.UiEventLogger
-import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.phone.SystemUIDialog
 import com.android.systemui.util.time.SystemClock
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.MutableSharedFlow
@@ -52,19 +54,24 @@
 import kotlinx.coroutines.withContext
 
 /** Dialog for showing active, connected and saved bluetooth devices. */
-@SysUISingleton
-internal class BluetoothTileDialog
-constructor(
-    private val bluetoothToggleInitialValue: Boolean,
-    private val initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
-    private val cachedContentHeight: Int,
-    private val bluetoothTileDialogCallback: BluetoothTileDialogCallback,
+class BluetoothTileDialogDelegate
+@AssistedInject
+internal constructor(
+    @Assisted private val context: Context,
+    @Assisted private val initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
+    @Assisted private val cachedContentHeight: Int,
+    @Assisted private val bluetoothToggleInitialValue: Boolean,
+    @Assisted private val bluetoothTileDialogCallback: BluetoothTileDialogCallback,
+    @Assisted private val dismissListener: Runnable,
     @Main private val mainDispatcher: CoroutineDispatcher,
     private val systemClock: SystemClock,
     private val uiEventLogger: UiEventLogger,
     private val logger: BluetoothTileDialogLogger,
-    context: Context,
-) : SystemUIDialog(context, DEFAULT_THEME, DEFAULT_DISMISS_ON_DEVICE_LOCK) {
+    private val systemuiDialogFactory: SystemUIDialog.Factory,
+    mainLayoutInflater: LayoutInflater,
+) : SystemUIDialog.Delegate {
+
+    private val layoutInflater = mainLayoutInflater.cloneInContext(context)
 
     private val mutableBluetoothStateToggle: MutableStateFlow<Boolean> =
         MutableStateFlow(bluetoothToggleInitialValue)
@@ -91,78 +98,72 @@
 
     private var lastItemRow: Int = -1
 
-    private lateinit var toggleView: Switch
-    private lateinit var subtitleTextView: TextView
-    private lateinit var autoOnToggle: Switch
-    private lateinit var autoOnToggleView: View
-    private lateinit var doneButton: View
-    private lateinit var seeAllButton: View
-    private lateinit var pairNewDeviceButton: View
-    private lateinit var deviceListView: RecyclerView
-    private lateinit var scrollViewContent: View
-    private lateinit var progressBarAnimation: ProgressBar
-    private lateinit var progressBarBackground: View
+    @AssistedFactory
+    internal interface Factory {
+        fun create(
+            context: Context,
+            initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
+            cachedContentHeight: Int,
+            bluetoothEnabled: Boolean,
+            dialogCallback: BluetoothTileDialogCallback,
+            dimissListener: Runnable
+        ): BluetoothTileDialogDelegate
+    }
 
-    override fun onCreate(savedInstanceState: Bundle?) {
-        super.onCreate(savedInstanceState)
+    override fun createDialog(): SystemUIDialog {
+        val dialog = systemuiDialogFactory.create(this, context)
+
+        return dialog
+    }
+
+    override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+        SystemUIDialog.registerDismissListener(dialog, dismissListener)
         uiEventLogger.log(BluetoothTileDialogUiEvent.BLUETOOTH_TILE_DIALOG_SHOWN)
 
-        LayoutInflater.from(context).inflate(R.layout.bluetooth_tile_dialog, null).apply {
+        layoutInflater.inflate(R.layout.bluetooth_tile_dialog, null).apply {
             accessibilityPaneTitle = context.getText(R.string.accessibility_desc_quick_settings)
-            setContentView(this)
+            dialog.setContentView(this)
         }
 
-        toggleView = requireViewById(R.id.bluetooth_toggle)
-        subtitleTextView = requireViewById(R.id.bluetooth_tile_dialog_subtitle) as TextView
-        autoOnToggle = requireViewById(R.id.bluetooth_auto_on_toggle)
-        autoOnToggleView = requireViewById(R.id.bluetooth_auto_on_toggle_layout)
-        doneButton = requireViewById(R.id.done_button)
-        seeAllButton = requireViewById(R.id.see_all_button)
-        pairNewDeviceButton = requireViewById(R.id.pair_new_device_button)
-        deviceListView = requireViewById<RecyclerView>(R.id.device_list)
+        setupToggle(dialog)
+        setupRecyclerView(dialog)
 
-        setupToggle()
-        setupRecyclerView()
-
-        subtitleTextView.text = context.getString(initialUiProperties.subTitleResId)
-        doneButton.setOnClickListener { dismiss() }
-        seeAllButton.setOnClickListener { bluetoothTileDialogCallback.onSeeAllClicked(it) }
-        pairNewDeviceButton.setOnClickListener {
+        getSubtitleTextView(dialog).text = context.getString(initialUiProperties.subTitleResId)
+        dialog.requireViewById<View>(R.id.done_button).setOnClickListener { dialog.dismiss() }
+        getSeeAllButton(dialog).setOnClickListener {
+            bluetoothTileDialogCallback.onSeeAllClicked(it)
+        }
+        getPairNewDeviceButton(dialog).setOnClickListener {
             bluetoothTileDialogCallback.onPairNewDeviceClicked(it)
         }
-        requireViewById<View>(R.id.scroll_view).apply {
-            scrollViewContent = this
+        getScrollViewContent(dialog).apply {
             minimumHeight =
                 resources.getDimensionPixelSize(initialUiProperties.scrollViewMinHeightResId)
             layoutParams.height = maxOf(cachedContentHeight, minimumHeight)
         }
-        progressBarAnimation = requireViewById(R.id.bluetooth_tile_dialog_progress_animation)
-        progressBarBackground = requireViewById(R.id.bluetooth_tile_dialog_progress_background)
     }
 
-    override fun start() {
+    override fun onStart(dialog: SystemUIDialog) {
         lastUiUpdateMs = systemClock.elapsedRealtime()
     }
 
-    override fun dismiss() {
-        if (::scrollViewContent.isInitialized) {
-            mutableContentHeight.tryEmit(scrollViewContent.measuredHeight)
-        }
-        super.dismiss()
+    override fun onStop(dialog: SystemUIDialog) {
+        mutableContentHeight.tryEmit(getScrollViewContent(dialog).measuredHeight)
     }
 
-    internal suspend fun animateProgressBar(animate: Boolean) {
+    internal suspend fun animateProgressBar(dialog: SystemUIDialog, animate: Boolean) {
         withContext(mainDispatcher) {
             if (animate) {
-                showProgressBar()
+                showProgressBar(dialog)
             } else {
                 delay(PROGRESS_BAR_ANIMATION_DURATION_MS)
-                hideProgressBar()
+                hideProgressBar(dialog)
             }
         }
     }
 
     internal suspend fun onDeviceItemUpdated(
+        dialog: SystemUIDialog,
         deviceItem: List<DeviceItem>,
         showSeeAll: Boolean,
         showPairNewDevice: Boolean
@@ -176,10 +177,11 @@
             }
             if (isActive) {
                 deviceItemAdapter.refreshDeviceItemList(deviceItem) {
-                    seeAllButton.visibility = if (showSeeAll) VISIBLE else GONE
-                    pairNewDeviceButton.visibility = if (showPairNewDevice) VISIBLE else GONE
+                    getSeeAllButton(dialog).visibility = if (showSeeAll) VISIBLE else GONE
+                    getPairNewDeviceButton(dialog).visibility =
+                        if (showPairNewDevice) VISIBLE else GONE
                     // Update the height after data is updated
-                    scrollViewContent.layoutParams.height = WRAP_CONTENT
+                    getScrollViewContent(dialog).layoutParams.height = WRAP_CONTENT
                     lastUiUpdateMs = systemClock.elapsedRealtime()
                     lastItemRow = itemRow
                     logger.logDeviceUiUpdate(lastUiUpdateMs - start)
@@ -189,29 +191,29 @@
     }
 
     internal fun onBluetoothStateUpdated(
+        dialog: SystemUIDialog,
         isEnabled: Boolean,
         uiProperties: BluetoothTileDialogViewModel.UiProperties
     ) {
-        toggleView.apply {
+        getToggleView(dialog).apply {
             isChecked = isEnabled
             setEnabled(true)
             alpha = ENABLED_ALPHA
         }
-        subtitleTextView.text = context.getString(uiProperties.subTitleResId)
-        autoOnToggleView.visibility = uiProperties.autoOnToggleVisibility
+        getSubtitleTextView(dialog).text = context.getString(uiProperties.subTitleResId)
+        getAutoOnToggleView(dialog).visibility = uiProperties.autoOnToggleVisibility
     }
 
-    internal fun onBluetoothAutoOnUpdated(isEnabled: Boolean) {
-        if (::autoOnToggle.isInitialized) {
-            autoOnToggle.apply {
-                isChecked = isEnabled
-                setEnabled(true)
-                alpha = ENABLED_ALPHA
-            }
+    internal fun onBluetoothAutoOnUpdated(dialog: SystemUIDialog, isEnabled: Boolean) {
+        getAutoOnToggle(dialog).apply {
+            isChecked = isEnabled
+            setEnabled(true)
+            alpha = ENABLED_ALPHA
         }
     }
 
-    private fun setupToggle() {
+    private fun setupToggle(dialog: SystemUIDialog) {
+        val toggleView = getToggleView(dialog)
         toggleView.isChecked = bluetoothToggleInitialValue
         toggleView.setOnCheckedChangeListener { view, isChecked ->
             mutableBluetoothStateToggle.value = isChecked
@@ -223,8 +225,8 @@
             uiEventLogger.log(BluetoothTileDialogUiEvent.BLUETOOTH_TOGGLE_CLICKED)
         }
 
-        autoOnToggleView.visibility = initialUiProperties.autoOnToggleVisibility
-        autoOnToggle.setOnCheckedChangeListener { view, isChecked ->
+        getAutoOnToggleView(dialog).visibility = initialUiProperties.autoOnToggleVisibility
+        getAutoOnToggle(dialog).setOnCheckedChangeListener { view, isChecked ->
             mutableBluetoothAutoOnToggle.value = isChecked
             view.apply {
                 isEnabled = false
@@ -234,30 +236,66 @@
         }
     }
 
-    private fun setupRecyclerView() {
-        deviceListView.apply {
+    private fun getToggleView(dialog: SystemUIDialog): Switch {
+        return dialog.requireViewById(R.id.bluetooth_toggle)
+    }
+
+    private fun getSubtitleTextView(dialog: SystemUIDialog): TextView {
+        return dialog.requireViewById(R.id.bluetooth_tile_dialog_subtitle)
+    }
+
+    private fun getSeeAllButton(dialog: SystemUIDialog): View {
+        return dialog.requireViewById(R.id.see_all_button)
+    }
+
+    private fun getPairNewDeviceButton(dialog: SystemUIDialog): View {
+        return dialog.requireViewById(R.id.pair_new_device_button)
+    }
+
+    private fun getDeviceListView(dialog: SystemUIDialog): RecyclerView {
+        return dialog.requireViewById(R.id.device_list)
+    }
+
+    private fun getAutoOnToggle(dialog: SystemUIDialog): Switch {
+        return dialog.requireViewById(R.id.bluetooth_auto_on_toggle)
+    }
+
+    private fun getAutoOnToggleView(dialog: SystemUIDialog): View {
+        return dialog.requireViewById(R.id.bluetooth_auto_on_toggle_layout)
+    }
+
+    private fun getProgressBarAnimation(dialog: SystemUIDialog): ProgressBar {
+        return dialog.requireViewById(R.id.bluetooth_tile_dialog_progress_animation)
+    }
+
+    private fun getProgressBarBackground(dialog: SystemUIDialog): View {
+        return dialog.requireViewById(R.id.bluetooth_tile_dialog_progress_animation)
+    }
+
+    private fun getScrollViewContent(dialog: SystemUIDialog): View {
+        return dialog.requireViewById(R.id.scroll_view)
+    }
+
+    private fun setupRecyclerView(dialog: SystemUIDialog) {
+        getDeviceListView(dialog).apply {
             layoutManager = LinearLayoutManager(context)
             adapter = deviceItemAdapter
         }
     }
 
-    private fun showProgressBar() {
-        if (
-            ::progressBarAnimation.isInitialized &&
-                ::progressBarBackground.isInitialized &&
-                progressBarAnimation.visibility != VISIBLE
-        ) {
+    private fun showProgressBar(dialog: SystemUIDialog) {
+        val progressBarAnimation = getProgressBarAnimation(dialog)
+        val progressBarBackground = getProgressBarBackground(dialog)
+        if (progressBarAnimation.visibility != VISIBLE) {
             progressBarAnimation.visibility = VISIBLE
             progressBarBackground.visibility = INVISIBLE
         }
     }
 
-    private fun hideProgressBar() {
-        if (
-            ::progressBarAnimation.isInitialized &&
-                ::progressBarBackground.isInitialized &&
-                progressBarAnimation.visibility != INVISIBLE
-        ) {
+    private fun hideProgressBar(dialog: SystemUIDialog) {
+        val progressBarAnimation = getProgressBarAnimation(dialog)
+        val progressBarBackground = getProgressBarBackground(dialog)
+        if (progressBarAnimation.visibility != INVISIBLE) {
             progressBarAnimation.visibility = INVISIBLE
             progressBarBackground.visibility = VISIBLE
         }
@@ -295,9 +333,7 @@
         private val asyncListDiffer = AsyncListDiffer(this, diffUtilCallback)
 
         override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DeviceItemViewHolder {
-            val view =
-                LayoutInflater.from(parent.context)
-                    .inflate(R.layout.bluetooth_device_item, parent, false)
+            val view = layoutInflater.inflate(R.layout.bluetooth_device_item, parent, false)
             return DeviceItemViewHolder(view)
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
index 5a14e5f..0486207 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
@@ -38,13 +38,11 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialog.Companion.ACTION_BLUETOOTH_DEVICE_DETAILS
-import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialog.Companion.ACTION_PAIR_NEW_DEVICE
-import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialog.Companion.ACTION_PREVIOUSLY_CONNECTED_DEVICE
-import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialog.Companion.MAX_DEVICE_ITEM_ENTRY
+import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialogDelegate.Companion.ACTION_BLUETOOTH_DEVICE_DETAILS
+import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialogDelegate.Companion.ACTION_PAIR_NEW_DEVICE
+import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialogDelegate.Companion.ACTION_PREVIOUSLY_CONNECTED_DEVICE
+import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialogDelegate.Companion.MAX_DEVICE_ITEM_ENTRY
 import com.android.systemui.res.R
-import com.android.systemui.statusbar.phone.SystemUIDialog
-import com.android.systemui.util.time.SystemClock
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
@@ -67,13 +65,12 @@
     private val bluetoothAutoOnInteractor: BluetoothAutoOnInteractor,
     private val dialogTransitionAnimator: DialogTransitionAnimator,
     private val activityStarter: ActivityStarter,
-    private val systemClock: SystemClock,
     private val uiEventLogger: UiEventLogger,
-    private val logger: BluetoothTileDialogLogger,
     @Application private val coroutineScope: CoroutineScope,
     @Main private val mainDispatcher: CoroutineDispatcher,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
     @Main private val sharedPreferences: SharedPreferences,
+    private val bluetoothDialogDelegateFactory: BluetoothTileDialogDelegate.Factory,
 ) : BluetoothTileDialogCallback {
 
     private var job: Job? = null
@@ -92,7 +89,8 @@
             coroutineScope.launch(mainDispatcher) {
                 var updateDeviceItemJob: Job?
                 var updateDialogUiJob: Job? = null
-                val dialog = createBluetoothTileDialog(context)
+                val dialogDelegate = createBluetoothTileDialog(context)
+                val dialog = dialogDelegate.createDialog()
 
                 view?.let {
                     dialogTransitionAnimator.showFromView(
@@ -118,13 +116,14 @@
                     .onEach {
                         updateDialogUiJob?.cancel()
                         updateDialogUiJob = launch {
-                            dialog.apply {
+                            dialogDelegate.apply {
                                 onDeviceItemUpdated(
+                                    dialog,
                                     it.take(MAX_DEVICE_ITEM_ENTRY),
                                     showSeeAll = it.size > MAX_DEVICE_ITEM_ENTRY,
                                     showPairNewDevice = bluetoothStateInteractor.isBluetoothEnabled
                                 )
-                                animateProgressBar(false)
+                                animateProgressBar(dialog, false)
                             }
                         }
                     }
@@ -134,7 +133,7 @@
                 // the device item list and animiate the progress bar.
                 deviceItemInteractor.deviceItemUpdateRequest
                     .onEach {
-                        dialog.animateProgressBar(true)
+                        dialogDelegate.animateProgressBar(dialog, true)
                         updateDeviceItemJob?.cancel()
                         updateDeviceItemJob = launch {
                             deviceItemInteractor.updateDeviceItems(
@@ -150,7 +149,8 @@
                 bluetoothStateInteractor.bluetoothStateUpdate
                     .filterNotNull()
                     .onEach {
-                        dialog.onBluetoothStateUpdated(
+                        dialogDelegate.onBluetoothStateUpdated(
+                            dialog,
                             it,
                             UiProperties.build(it, isAutoOnToggleFeatureAvailable())
                         )
@@ -166,20 +166,20 @@
 
                 // bluetoothStateToggle is emitted when user toggles the bluetooth state switch,
                 // send the new value to the bluetoothStateInteractor and animate the progress bar.
-                dialog.bluetoothStateToggle
+                dialogDelegate.bluetoothStateToggle
                     .onEach {
-                        dialog.animateProgressBar(true)
+                        dialogDelegate.animateProgressBar(dialog, true)
                         bluetoothStateInteractor.isBluetoothEnabled = it
                     }
                     .launchIn(this)
 
                 // deviceItemClick is emitted when user clicked on a device item.
-                dialog.deviceItemClick
+                dialogDelegate.deviceItemClick
                     .onEach { deviceItemInteractor.updateDeviceItemOnClick(it) }
                     .launchIn(this)
 
                 // contentHeight is emitted when the dialog is dismissed.
-                dialog.contentHeight
+                dialogDelegate.contentHeight
                     .onEach {
                         withContext(backgroundDispatcher) {
                             sharedPreferences.edit().putInt(CONTENT_HEIGHT_PREF_KEY, it).apply()
@@ -191,12 +191,12 @@
                     // bluetoothAutoOnUpdate is emitted when bluetooth auto on on/off state is
                     // changed.
                     bluetoothAutoOnInteractor.isEnabled
-                        .onEach { dialog.onBluetoothAutoOnUpdated(it) }
+                        .onEach { dialogDelegate.onBluetoothAutoOnUpdated(dialog, it) }
                         .launchIn(this)
 
                     // bluetoothAutoOnToggle is emitted when user toggles the bluetooth auto on
                     // switch, send the new value to the bluetoothAutoOnInteractor.
-                    dialog.bluetoothAutoOnToggle
+                    dialogDelegate.bluetoothAutoOnToggle
                         .filterNotNull()
                         .onEach { bluetoothAutoOnInteractor.setEnabled(it) }
                         .launchIn(this)
@@ -206,7 +206,7 @@
             }
     }
 
-    private suspend fun createBluetoothTileDialog(context: Context): BluetoothTileDialog {
+    private suspend fun createBluetoothTileDialog(context: Context): BluetoothTileDialogDelegate {
         val cachedContentHeight =
             withContext(backgroundDispatcher) {
                 sharedPreferences.getInt(
@@ -215,21 +215,17 @@
                 )
             }
 
-        return BluetoothTileDialog(
+        return bluetoothDialogDelegateFactory.create(
+            context,
+            UiProperties.build(
                 bluetoothStateInteractor.isBluetoothEnabled,
-                UiProperties.build(
-                    bluetoothStateInteractor.isBluetoothEnabled,
-                    isAutoOnToggleFeatureAvailable()
-                ),
-                cachedContentHeight,
-                this@BluetoothTileDialogViewModel,
-                mainDispatcher,
-                systemClock,
-                uiEventLogger,
-                logger,
-                context
-            )
-            .apply { SystemUIDialog.registerDismissListener(this) { cancelJob() } }
+                isAutoOnToggleFeatureAvailable()
+            ),
+            cachedContentHeight,
+            bluetoothStateInteractor.isBluetoothEnabled,
+            this@BluetoothTileDialogViewModel,
+            { cancelJob() }
+        )
     }
 
     override fun onDeviceItemGearClicked(deviceItem: DeviceItem, view: View) {
@@ -308,7 +304,7 @@
     }
 }
 
-internal interface BluetoothTileDialogCallback {
+interface BluetoothTileDialogCallback {
     fun onDeviceItemGearClicked(deviceItem: DeviceItem, view: View)
     fun onSeeAllClicked(view: View)
     fun onPairNewDeviceClicked(view: View)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactory.kt
index 1c9be0f..f13ecf3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactory.kt
@@ -21,6 +21,7 @@
 import android.media.AudioManager
 import com.android.settingslib.bluetooth.BluetoothUtils
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.flags.Flags
 import com.android.systemui.res.R
 
 private val backgroundOn = R.drawable.settingslib_switch_bar_bg_on
@@ -36,6 +37,7 @@
 /** Factories to create different types of Bluetooth device items from CachedBluetoothDevice. */
 internal abstract class DeviceItemFactory {
     abstract fun isFilterMatched(
+        context: Context,
         cachedDevice: CachedBluetoothDevice,
         audioManager: AudioManager?
     ): Boolean
@@ -45,6 +47,7 @@
 
 internal class ActiveMediaDeviceItemFactory : DeviceItemFactory() {
     override fun isFilterMatched(
+        context: Context,
         cachedDevice: CachedBluetoothDevice,
         audioManager: AudioManager?
     ): Boolean {
@@ -71,6 +74,7 @@
 
 internal class AvailableMediaDeviceItemFactory : DeviceItemFactory() {
     override fun isFilterMatched(
+        context: Context,
         cachedDevice: CachedBluetoothDevice,
         audioManager: AudioManager?
     ): Boolean {
@@ -99,10 +103,18 @@
 
 internal class ConnectedDeviceItemFactory : DeviceItemFactory() {
     override fun isFilterMatched(
+        context: Context,
         cachedDevice: CachedBluetoothDevice,
         audioManager: AudioManager?
     ): Boolean {
-        return BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager)
+        return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
+            !BluetoothUtils.isExclusivelyManagedBluetoothDevice(
+                context,
+                cachedDevice.getDevice()
+            ) && BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager)
+        } else {
+            BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager)
+        }
     }
 
     override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
@@ -125,10 +137,18 @@
 
 internal class SavedDeviceItemFactory : DeviceItemFactory() {
     override fun isFilterMatched(
+        context: Context,
         cachedDevice: CachedBluetoothDevice,
         audioManager: AudioManager?
     ): Boolean {
-        return cachedDevice.bondState == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected
+        return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
+            !BluetoothUtils.isExclusivelyManagedBluetoothDevice(
+                context,
+                cachedDevice.getDevice()
+            ) && cachedDevice.bondState == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected
+        } else {
+            cachedDevice.bondState == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected
+        }
     }
 
     override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractor.kt
index fcd45a6..1df496b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractor.kt
@@ -133,7 +133,7 @@
                 bluetoothTileDialogRepository.cachedDevices
                     .mapNotNull { cachedDevice ->
                         deviceItemFactoryList
-                            .firstOrNull { it.isFilterMatched(cachedDevice, audioManager) }
+                            .firstOrNull { it.isFilterMatched(context, cachedDevice, audioManager) }
                             ?.create(context, cachedDevice)
                     }
                     .sort(displayPriority, bluetoothAdapter?.mostRecentlyConnectedDevices)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileDataInteractor.kt
new file mode 100644
index 0000000..736e1a5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileDataInteractor.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.rotation.domain.interactor
+
+import android.Manifest
+import android.content.pm.PackageManager
+import android.content.res.Resources
+import android.os.UserHandle
+import com.android.systemui.camera.data.repository.CameraAutoRotateRepository
+import com.android.systemui.camera.data.repository.CameraSensorPrivacyRepository
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
+import com.android.systemui.qs.tiles.impl.rotation.domain.model.RotationLockTileModel
+import com.android.systemui.statusbar.policy.BatteryController
+import com.android.systemui.statusbar.policy.RotationLockController
+import com.android.systemui.util.kotlin.isBatteryPowerSaveEnabled
+import com.android.systemui.util.kotlin.isRotationLockEnabled
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flowOf
+
+/** Observes rotation lock state changes providing the [RotationLockTileModel]. */
+class RotationLockTileDataInteractor
+@Inject
+constructor(
+    private val rotationLockController: RotationLockController,
+    private val batteryController: BatteryController,
+    private val cameraAutoRotateRepository: CameraAutoRotateRepository,
+    private val cameraSensorPrivacyRepository: CameraSensorPrivacyRepository,
+    private val packageManager: PackageManager,
+    @Main private val resources: Resources,
+) : QSTileDataInteractor<RotationLockTileModel> {
+
+    override fun tileData(
+        user: UserHandle,
+        triggers: Flow<DataUpdateTrigger>
+    ): Flow<RotationLockTileModel> =
+        combine(
+            rotationLockController.isRotationLockEnabled(),
+            cameraSensorPrivacyRepository.isEnabled(user),
+            batteryController.isBatteryPowerSaveEnabled(),
+            cameraAutoRotateRepository.isCameraAutoRotateSettingEnabled(user)
+        ) {
+            isRotationLockEnabled,
+            isCamPrivacySensorEnabled,
+            isBatteryPowerSaveEnabled,
+            isCameraAutoRotateEnabled,
+            ->
+            RotationLockTileModel(
+                isRotationLockEnabled,
+                isCameraRotationEnabled(
+                    isBatteryPowerSaveEnabled,
+                    isCamPrivacySensorEnabled,
+                    isCameraAutoRotateEnabled
+                ),
+            )
+        }
+
+    override fun availability(user: UserHandle): Flow<Boolean> = flowOf(true)
+
+    private fun hasSufficientPermission(): Boolean {
+        val rotationPackage: String = packageManager.rotationResolverPackageName
+        return rotationPackage != null &&
+            packageManager.checkPermission(Manifest.permission.CAMERA, rotationPackage) ==
+                PackageManager.PERMISSION_GRANTED
+    }
+
+    private fun isCameraRotationEnabled(
+        isBatteryPowerSaverModeOn: Boolean,
+        isCameraSensorPrivacyEnabled: Boolean,
+        isCameraAutoRotateEnabled: Boolean
+    ): Boolean =
+        resources.getBoolean(com.android.internal.R.bool.config_allowRotationResolver) &&
+            !isBatteryPowerSaverModeOn &&
+            !isCameraSensorPrivacyEnabled &&
+            hasSufficientPermission() &&
+            isCameraAutoRotateEnabled
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileUserActionInteractor.kt
new file mode 100644
index 0000000..8530926
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileUserActionInteractor.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.rotation.domain.interactor
+
+import android.content.Intent
+import android.provider.Settings
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.interactor.QSTileInput
+import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
+import com.android.systemui.qs.tiles.impl.rotation.domain.model.RotationLockTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
+import com.android.systemui.statusbar.policy.RotationLockController
+import javax.inject.Inject
+
+/** Handles rotation lock tile clicks. */
+class RotationLockTileUserActionInteractor
+@Inject
+constructor(
+    private val controller: RotationLockController,
+    private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler,
+) : QSTileUserActionInteractor<RotationLockTileModel> {
+
+    override suspend fun handleInput(input: QSTileInput<RotationLockTileModel>) {
+        with(input) {
+            when (action) {
+                is QSTileUserAction.Click -> {
+                    controller.setRotationLocked(!data.isRotationLocked, CALLER)
+                }
+                is QSTileUserAction.LongClick -> {
+                    qsTileIntentUserActionHandler.handle(
+                        action.view,
+                        Intent(Settings.ACTION_AUTO_ROTATE_SETTINGS)
+                    )
+                }
+            }
+        }
+    }
+
+    companion object {
+        private const val CALLER = "QSTileUserActionInteractor#handleInput"
+    }
+}
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/model/RotationLockTileModel.kt
similarity index 74%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
copy to packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/model/RotationLockTileModel.kt
index 8ad0a08..32e6cb8c 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/model/RotationLockTileModel.kt
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.systemui.volume.panel.component.mediaoutput
+package com.android.systemui.qs.tiles.impl.rotation.domain.model
 
-import dagger.Module
-
-@Module interface MediaOutputModule
+/** Model for rotation lock tile */
+class RotationLockTileModel(
+    val isRotationLocked: Boolean,
+    val isCameraRotationEnabled: Boolean,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapper.kt
new file mode 100644
index 0000000..070cdef
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapper.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.rotation.ui.mapper
+
+import android.content.res.Resources
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
+import com.android.systemui.qs.tiles.impl.rotation.domain.model.RotationLockTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.policy.DevicePostureController
+import javax.inject.Inject
+
+/** Maps [RotationLockTileModel] to [QSTileState]. */
+class RotationLockTileMapper
+@Inject
+constructor(
+    @Main private val resources: Resources,
+    private val theme: Resources.Theme,
+    private val devicePostureController: DevicePostureController
+) : QSTileDataToStateMapper<RotationLockTileModel> {
+    override fun map(config: QSTileConfig, data: RotationLockTileModel): QSTileState =
+        QSTileState.build(resources, theme, config.uiConfig) {
+            this.label = resources.getString(R.string.quick_settings_rotation_unlocked_label)
+            this.contentDescription =
+                resources.getString(R.string.accessibility_quick_settings_rotation)
+
+            if (data.isRotationLocked) {
+                activationState = QSTileState.ActivationState.INACTIVE
+                this.secondaryLabel = EMPTY_SECONDARY_STRING
+                this.icon = {
+                    Icon.Loaded(
+                        resources.getDrawable(R.drawable.qs_auto_rotate_icon_off, theme),
+                        contentDescription = null
+                    )
+                }
+            } else {
+                activationState = QSTileState.ActivationState.ACTIVE
+                this.secondaryLabel =
+                    if (data.isCameraRotationEnabled) {
+                        resources.getString(R.string.rotation_lock_camera_rotation_on)
+                    } else {
+                        EMPTY_SECONDARY_STRING
+                    }
+                this.icon = {
+                    Icon.Loaded(
+                        resources.getDrawable(R.drawable.qs_auto_rotate_icon_on, theme),
+                        contentDescription = null
+                    )
+                }
+            }
+            if (isDeviceFoldable()) {
+                this.secondaryLabel = getSecondaryLabelWithPosture(this.activationState)
+            }
+            this.stateDescription = this.secondaryLabel
+            this.sideViewIcon = QSTileState.SideViewIcon.None
+            supportedActions =
+                setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
+        }
+
+    private fun isDeviceFoldable(): Boolean {
+        val intArray = resources.getIntArray(com.android.internal.R.array.config_foldedDeviceStates)
+        return intArray.isNotEmpty()
+    }
+
+    private fun getSecondaryLabelWithPosture(activationState: QSTileState.ActivationState): String {
+        val stateNames = resources.getStringArray(R.array.tile_states_rotation)
+        val stateName =
+            stateNames[
+                if (activationState == QSTileState.ActivationState.ACTIVE) ON_INDEX else OFF_INDEX]
+        val posture =
+            if (
+                devicePostureController.devicePosture ==
+                    DevicePostureController.DEVICE_POSTURE_CLOSED
+            )
+                resources.getString(R.string.quick_settings_rotation_posture_folded)
+            else resources.getString(R.string.quick_settings_rotation_posture_unfolded)
+
+        return resources.getString(
+            R.string.rotation_tile_with_posture_secondary_label_template,
+            stateName,
+            posture
+        )
+    }
+
+    private companion object {
+        const val EMPTY_SECONDARY_STRING = ""
+        const val OFF_INDEX = 1
+        const val ON_INDEX = 2
+    }
+}
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 17454a9..34f66b8 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
@@ -17,14 +17,16 @@
 package com.android.systemui.qs.ui.viewmodel
 
 import androidx.lifecycle.LifecycleOwner
+import com.android.compose.animation.scene.Back
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.SwipeDirection
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.qs.FooterActionsController
 import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
 import com.android.systemui.qs.ui.adapter.QSSceneAdapter
-import com.android.systemui.scene.shared.model.Direction
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.shared.model.UserAction
-import com.android.systemui.scene.shared.model.UserActionResult
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
 import java.util.concurrent.atomic.AtomicBoolean
@@ -45,13 +47,11 @@
     val destinationScenes =
         qsSceneAdapter.isCustomizing.map { customizing ->
             if (customizing) {
-                mapOf<UserAction, UserActionResult>(
-                    UserAction.Back to UserActionResult(SceneKey.QuickSettings)
-                )
+                mapOf<UserAction, UserActionResult>(Back to UserActionResult(Scenes.QuickSettings))
             } else {
                 mapOf(
-                    UserAction.Back to UserActionResult(SceneKey.Shade),
-                    UserAction.Swipe(Direction.UP) to UserActionResult(SceneKey.Shade),
+                    Back to UserActionResult(Scenes.Shade),
+                    Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade),
                 )
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 000f3c09d..5f8b5dd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -221,7 +221,7 @@
                         // If scene framework is enabled, set the scene container window to
                         // visible and let the touch "slip" into that window.
                         if (mSceneContainerFlags.isEnabled()) {
-                            mSceneInteractor.get().setVisible(true, "swipe down on launcher");
+                            mSceneInteractor.get().onRemoteUserInteractionStarted("launcher swipe");
                         } else {
                             mShadeViewControllerLazy.get().startInputFocusTransfer();
                         }
diff --git a/packages/SystemUI/src/com/android/systemui/rotationlock/RotationLockNewModule.kt b/packages/SystemUI/src/com/android/systemui/rotationlock/RotationLockNewModule.kt
new file mode 100644
index 0000000..eb64dd6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/rotationlock/RotationLockNewModule.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.rotationlock
+
+import com.android.systemui.camera.CameraRotationModule
+import com.android.systemui.qs.QsEventLogger
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelFactory
+import com.android.systemui.qs.tiles.impl.rotation.domain.interactor.RotationLockTileDataInteractor
+import com.android.systemui.qs.tiles.impl.rotation.domain.interactor.RotationLockTileUserActionInteractor
+import com.android.systemui.qs.tiles.impl.rotation.domain.model.RotationLockTileModel
+import com.android.systemui.qs.tiles.impl.rotation.ui.mapper.RotationLockTileMapper
+import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
+import com.android.systemui.res.R
+import dagger.Module
+import dagger.Provides
+import dagger.multibindings.IntoMap
+import dagger.multibindings.StringKey
+
+@Module(includes = [CameraRotationModule::class])
+interface RotationLockNewModule {
+    companion object {
+        private const val ROTATION_TILE_SPEC = "rotation"
+
+        /** Inject rotation tile config */
+        @Provides
+        @IntoMap
+        @StringKey(ROTATION_TILE_SPEC)
+        fun provideRotationTileConfig(uiEventLogger: QsEventLogger): QSTileConfig =
+            QSTileConfig(
+                tileSpec = TileSpec.create(ROTATION_TILE_SPEC),
+                uiConfig =
+                    QSTileUIConfig.Resource(
+                        iconRes = R.drawable.qs_auto_rotate_icon_off,
+                        labelRes = R.string.quick_settings_rotation_unlocked_label,
+                    ),
+                instanceId = uiEventLogger.getNewInstanceId(),
+            )
+
+        /** Inject Rotation tile into tileViewModelMap in QSModule */
+        @Provides
+        @IntoMap
+        @StringKey(ROTATION_TILE_SPEC)
+        fun provideRotationTileViewModel(
+            factory: QSTileViewModelFactory.Static<RotationLockTileModel>,
+            mapper: RotationLockTileMapper,
+            stateInteractor: RotationLockTileDataInteractor,
+            userActionInteractor: RotationLockTileUserActionInteractor
+        ): QSTileViewModel =
+            factory.create(
+                TileSpec.create(ROTATION_TILE_SPEC),
+                userActionInteractor,
+                stateInteractor,
+                mapper,
+            )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
index 356eb85..afd0746 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
@@ -18,7 +18,7 @@
 
 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 com.android.systemui.scene.shared.model.Scenes
 import dagger.Module
 import dagger.Provides
 
@@ -44,11 +44,11 @@
             // last one is top-most.
             sceneKeys =
                 listOf(
-                    SceneKey.Gone,
-                    SceneKey.QuickSettings,
-                    SceneKey.Shade,
+                    Scenes.Gone,
+                    Scenes.QuickSettings,
+                    Scenes.Shade,
                 ),
-            initialSceneKey = SceneKey.Gone,
+            initialSceneKey = Scenes.Gone,
         )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
index c7d3a4a..62b0914 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
@@ -17,11 +17,12 @@
 package com.android.systemui.scene
 
 import com.android.systemui.CoreStartable
+import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlagsModule
 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 com.android.systemui.scene.shared.model.Scenes
 import dagger.Binds
 import dagger.Module
 import dagger.Provides
@@ -34,6 +35,7 @@
         [
             BouncerSceneModule::class,
             CommunalSceneModule::class,
+            ComposeBouncerFlagsModule::class,
             EmptySceneModule::class,
             GoneSceneModule::class,
             LockscreenSceneModule::class,
@@ -65,14 +67,14 @@
                 // last one is top-most.
                 sceneKeys =
                     listOf(
-                        SceneKey.Gone,
-                        SceneKey.Communal,
-                        SceneKey.Lockscreen,
-                        SceneKey.Bouncer,
-                        SceneKey.QuickSettings,
-                        SceneKey.Shade,
+                        Scenes.Gone,
+                        Scenes.Communal,
+                        Scenes.Lockscreen,
+                        Scenes.Bouncer,
+                        Scenes.QuickSettings,
+                        Scenes.Shade,
                     ),
-                initialSceneKey = SceneKey.Lockscreen,
+                initialSceneKey = Scenes.Lockscreen,
             )
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt
index c10e51b..0665c9e 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt
@@ -18,7 +18,7 @@
 
 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 com.android.systemui.scene.shared.model.Scenes
 import dagger.Module
 import dagger.Provides
 
@@ -44,11 +44,11 @@
             // last one is top-most.
             sceneKeys =
                 listOf(
-                    SceneKey.Gone,
-                    SceneKey.Lockscreen,
-                    SceneKey.Bouncer,
+                    Scenes.Gone,
+                    Scenes.Lockscreen,
+                    Scenes.Bouncer,
                 ),
-            initialSceneKey = SceneKey.Lockscreen,
+            initialSceneKey = Scenes.Lockscreen,
         )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
index a302194..994b012 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
@@ -18,12 +18,12 @@
 
 package com.android.systemui.scene.data.repository
 
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.TransitionKey
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.scene.shared.model.ObservableTransitionState
 import com.android.systemui.scene.shared.model.SceneContainerConfig
 import com.android.systemui.scene.shared.model.SceneDataSource
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.shared.model.TransitionKey
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -49,6 +49,13 @@
     private val _isVisible = MutableStateFlow(true)
     val isVisible: StateFlow<Boolean> = _isVisible.asStateFlow()
 
+    /**
+     * Whether there's an ongoing remotely-initiated user interaction.
+     *
+     * For more information see the logic in `SceneInteractor` that mutates this.
+     */
+    val isRemoteUserInteractionOngoing = MutableStateFlow(false)
+
     private val defaultTransitionState = ObservableTransitionState.Idle(config.initialSceneKey)
     private val _transitionState = MutableStateFlow<Flow<ObservableTransitionState>?>(null)
     val transitionState: StateFlow<ObservableTransitionState> =
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractor.kt
new file mode 100644
index 0000000..3a5ea5c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractor.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.scene.domain.interactor
+
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.data.repository.ShadeRepository
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+
+@SysUISingleton
+class PanelExpansionInteractor
+@Inject
+constructor(
+    sceneInteractor: SceneInteractor,
+    shadeRepository: ShadeRepository,
+) {
+
+    /**
+     * The amount by which the "panel" has been expanded (`0` when fully collapsed, `1` when fully
+     * expanded).
+     *
+     * This is a legacy concept from the time when the "panel" included the notification/QS shades
+     * as well as the keyguard (lockscreen and bouncer). This value is meant only for
+     * backwards-compatibility and should not be consumed by newer code.
+     */
+    @Deprecated("Use SceneInteractor.currentScene instead.")
+    val legacyPanelExpansion: Flow<Float> =
+        if (SceneContainerFlag.isEnabled) {
+            sceneInteractor.transitionState.flatMapLatest { state ->
+                when (state) {
+                    is ObservableTransitionState.Idle ->
+                        flowOf(
+                            if (state.scene != Scenes.Gone) {
+                                // When resting on a non-Gone scene, the panel is fully expanded.
+                                1f
+                            } else {
+                                // When resting on the Gone scene, the panel is considered fully
+                                // collapsed.
+                                0f
+                            }
+                        )
+                    is ObservableTransitionState.Transition ->
+                        when {
+                            state.fromScene == Scenes.Gone ->
+                                if (state.toScene.isExpandable()) {
+                                    // Moving from Gone to a scene that can animate-expand has a
+                                    // panel
+                                    // expansion
+                                    // that tracks with the transition.
+                                    state.progress
+                                } else {
+                                    // Moving from Gone to a scene that doesn't animate-expand
+                                    // immediately makes
+                                    // the panel fully expanded.
+                                    flowOf(1f)
+                                }
+                            state.toScene == Scenes.Gone ->
+                                if (state.fromScene.isExpandable()) {
+                                    // Moving to Gone from a scene that can animate-expand has a
+                                    // panel
+                                    // expansion
+                                    // that tracks with the transition.
+                                    state.progress.map { 1 - it }
+                                } else {
+                                    // Moving to Gone from a scene that doesn't animate-expand
+                                    // immediately makes
+                                    // the panel fully collapsed.
+                                    flowOf(0f)
+                                }
+                            else -> flowOf(1f)
+                        }
+                }
+            }
+        } else {
+            shadeRepository.legacyShadeExpansion
+        }
+
+    private fun SceneKey.isExpandable(): Boolean {
+        return this == Scenes.Shade || this == Scenes.QuickSettings
+    }
+}
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 0add444..75bf131 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
@@ -16,14 +16,15 @@
 
 package com.android.systemui.scene.domain.interactor
 
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.TransitionKey
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
 import com.android.systemui.scene.data.repository.SceneContainerRepository
 import com.android.systemui.scene.shared.logger.SceneLogger
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.shared.model.TransitionKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.util.kotlin.pairwiseBy
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -31,6 +32,7 @@
 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.map
@@ -121,7 +123,21 @@
             )
 
     /** Whether the scene container is visible. */
-    val isVisible: StateFlow<Boolean> = repository.isVisible
+    val isVisible: StateFlow<Boolean> =
+        combine(
+                repository.isVisible,
+                repository.isRemoteUserInteractionOngoing,
+            ) { isVisible, isRemoteUserInteractionOngoing ->
+                isVisibleInternal(
+                    raw = isVisible,
+                    isRemoteUserInteractionOngoing = isRemoteUserInteractionOngoing,
+                )
+            }
+            .stateIn(
+                scope = applicationScope,
+                started = SharingStarted.WhileSubscribed(),
+                initialValue = isVisibleInternal()
+            )
 
     /**
      * Returns the keys of all scenes in the container.
@@ -140,12 +156,13 @@
      * desired scene. Once enough of the transition has occurred, the [currentScene] will become
      * [toScene] (unless the transition is canceled by user action or another call to this method).
      */
+    @JvmOverloads
     fun changeScene(
         toScene: SceneKey,
         loggingReason: String,
         transitionKey: TransitionKey? = null,
     ) {
-        check(toScene != SceneKey.Gone || deviceUnlockedInteractor.isDeviceUnlocked.value) {
+        check(toScene != Scenes.Gone || deviceUnlockedInteractor.isDeviceUnlocked.value) {
             "Cannot change to the Gone scene while the device is locked. Logging reason for scene" +
                 " change was: $loggingReason"
         }
@@ -164,7 +181,14 @@
         repository.changeScene(toScene, transitionKey)
     }
 
-    /** Sets the visibility of the container. */
+    /**
+     * Sets the visibility of the container.
+     *
+     * Please do not call this from outside of the scene framework. If you are trying to force the
+     * visibility to visible or invisible, prefer making changes to the existing caller of this
+     * method or to upstream state used to calculate [isVisible]; for an example of the latter,
+     * please see [onRemoteUserInteractionStarted] and [onUserInteractionFinished].
+     */
     fun setVisible(isVisible: Boolean, loggingReason: String) {
         val wasVisible = repository.isVisible.value
         if (wasVisible == isVisible) {
@@ -180,6 +204,31 @@
     }
 
     /**
+     * Notifies that a remote user interaction has begun.
+     *
+     * This is a user interaction that originates outside of the UI of the scene container and
+     * possibly outside of the System UI process itself.
+     *
+     * As an example, consider the dragging that can happen in the launcher that expands the shade.
+     * This is a user interaction that begins remotely (as it starts in the launcher process) and is
+     * then rerouted by window manager to System UI. While the user interaction definitely continues
+     * within the System UI process and code, it also originates remotely.
+     */
+    fun onRemoteUserInteractionStarted(loggingReason: String) {
+        logger.logRemoteUserInteractionStarted(loggingReason)
+        repository.isRemoteUserInteractionOngoing.value = true
+    }
+
+    /**
+     * Notifies that the current user interaction (internally or remotely started, see
+     * [onRemoteUserInteractionStarted]) has finished.
+     */
+    fun onUserInteractionFinished() {
+        logger.logUserInteractionFinished()
+        repository.isRemoteUserInteractionOngoing.value = false
+    }
+
+    /**
      * Binds the given flow so the system remembers it.
      *
      * Note that you must call is with `null` when the UI is done or risk a memory leak.
@@ -187,4 +236,11 @@
     fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) {
         repository.setTransitionState(transitionState)
     }
+
+    private fun isVisibleInternal(
+        raw: Boolean = repository.isVisible.value,
+        isRemoteUserInteractionOngoing: Boolean = repository.isRemoteUserInteractionOngoing.value,
+    ): Boolean {
+        return raw || isRemoteUserInteractionOngoing
+    }
 }
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
index 1c37908..c736707 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.scene.domain.interactor
 
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
@@ -24,8 +25,7 @@
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.scene.data.repository.WindowRootViewVisibilityRepository
 import com.android.systemui.scene.shared.flag.SceneContainerFlags
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.statusbar.NotificationPresenter
 import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
 import com.android.systemui.statusbar.notification.init.NotificationsController
@@ -77,12 +77,12 @@
                 .map { state ->
                     when (state) {
                         is ObservableTransitionState.Idle ->
-                            state.scene == SceneKey.Shade || state.scene == SceneKey.Lockscreen
+                            state.scene == Scenes.Shade || state.scene == Scenes.Lockscreen
                         is ObservableTransitionState.Transition ->
-                            state.toScene == SceneKey.Shade ||
-                                state.toScene == SceneKey.Lockscreen ||
-                                state.fromScene == SceneKey.Shade ||
-                                state.fromScene == SceneKey.Lockscreen
+                            state.toScene == Scenes.Shade ||
+                                state.toScene == Scenes.Lockscreen ||
+                                state.fromScene == Scenes.Shade ||
+                                state.fromScene == Scenes.Lockscreen
                     }
                 }
                 .distinctUntilChanged()
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 b642d38..6df57ed 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
@@ -19,6 +19,8 @@
 package com.android.systemui.scene.domain.startable
 
 import android.app.StatusBarManager
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.CoreStartable
 import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
 import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
@@ -26,6 +28,7 @@
 import com.android.systemui.bouncer.domain.interactor.SimBouncerInteractor
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.classifier.FalsingCollectorActual
+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.DisplayId
@@ -34,12 +37,13 @@
 import com.android.systemui.model.SceneContainerPlugin
 import com.android.systemui.model.SysUiState
 import com.android.systemui.model.updateFlags
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.FalsingManager.FalsingBeliefListener
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.scene.shared.logger.SceneLogger
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor
 import com.android.systemui.statusbar.notification.stack.shared.flexiNotifsEnabled
@@ -53,6 +57,7 @@
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
@@ -82,6 +87,7 @@
     @DisplayId private val displayId: Int,
     private val sceneLogger: SceneLogger,
     @FalsingCollectorActual private val falsingCollector: FalsingCollector,
+    private val falsingManager: FalsingManager,
     private val powerInteractor: PowerInteractor,
     private val simBouncerInteractor: Lazy<SimBouncerInteractor>,
     private val authenticationInteractor: Lazy<AuthenticationInteractor>,
@@ -98,6 +104,7 @@
             automaticallySwitchScenes()
             hydrateSystemUiState()
             collectFalsingSignals()
+            respondToFalsingDetections()
             hydrateWindowFocus()
             hydrateInteractionState()
         } else {
@@ -134,14 +141,14 @@
                             .mapNotNull { state ->
                                 when (state) {
                                     is ObservableTransitionState.Idle -> {
-                                        if (state.scene != SceneKey.Gone) {
+                                        if (state.scene != Scenes.Gone) {
                                             true to "scene is not Gone"
                                         } else {
                                             false to "scene is Gone"
                                         }
                                     }
                                     is ObservableTransitionState.Transition -> {
-                                        if (state.fromScene == SceneKey.Gone) {
+                                        if (state.fromScene == Scenes.Gone) {
                                             true to "scene transitioning away from Gone"
                                         } else {
                                             null
@@ -174,9 +181,9 @@
         applicationScope.launch {
             // TODO (b/308001302): Move this to a bouncer specific interactor.
             bouncerInteractor.onImeHiddenByUser.collectLatest {
-                if (sceneInteractor.currentScene.value == SceneKey.Bouncer) {
+                if (sceneInteractor.currentScene.value == Scenes.Bouncer) {
                     sceneInteractor.changeScene(
-                        toScene = SceneKey.Lockscreen,
+                        toScene = Scenes.Lockscreen,
                         loggingReason = "IME hidden",
                     )
                 }
@@ -190,13 +197,13 @@
                 when {
                     isAnySimLocked -> {
                         switchToScene(
-                            targetSceneKey = SceneKey.Bouncer,
+                            targetSceneKey = Scenes.Bouncer,
                             loggingReason = "Need to authenticate locked SIM card."
                         )
                     }
                     isUnlocked && canSwipeToEnter == false -> {
                         switchToScene(
-                            targetSceneKey = SceneKey.Gone,
+                            targetSceneKey = Scenes.Gone,
                             loggingReason =
                                 "All SIM cards unlocked and device already" +
                                     " unlocked and lockscreen doesn't require a swipe to dismiss."
@@ -204,7 +211,7 @@
                     }
                     else -> {
                         switchToScene(
-                            targetSceneKey = SceneKey.Lockscreen,
+                            targetSceneKey = Scenes.Lockscreen,
                             loggingReason =
                                 "All SIM cards unlocked and device still locked" +
                                     " or lockscreen still requires a swipe to dismiss."
@@ -225,8 +232,8 @@
                                     transitionState.toScene,
                                 )
                         }
-                    val isOnLockscreen = renderedScenes.contains(SceneKey.Lockscreen)
-                    val isOnBouncer = renderedScenes.contains(SceneKey.Bouncer)
+                    val isOnLockscreen = renderedScenes.contains(Scenes.Lockscreen)
+                    val isOnBouncer = renderedScenes.contains(Scenes.Bouncer)
                     if (!isUnlocked) {
                         return@mapNotNull if (isOnLockscreen || isOnBouncer) {
                             // Already on lockscreen or bouncer, no need to change scenes.
@@ -234,7 +241,7 @@
                         } else {
                             // The device locked while on a scene that's not Lockscreen or Bouncer,
                             // go to Lockscreen.
-                            SceneKey.Lockscreen to
+                            Scenes.Lockscreen to
                                 "device locked in non-Lockscreen and non-Bouncer scene"
                         }
                     }
@@ -244,7 +251,7 @@
                     when {
                         isOnBouncer ->
                             // When the device becomes unlocked in Bouncer, go to Gone.
-                            SceneKey.Gone to "device was unlocked in Bouncer scene"
+                            Scenes.Gone to "device was unlocked in Bouncer scene"
                         isOnLockscreen ->
                             // The lockscreen should be dismissed automatically in 2 scenarios:
                             // 1. When face auth bypass is enabled and authentication happens while
@@ -256,11 +263,11 @@
                             //    authentication attempt.
                             when {
                                 isBypassEnabled ->
-                                    SceneKey.Gone to
+                                    Scenes.Gone to
                                         "device has been unlocked on lockscreen with bypass" +
                                             " enabled"
                                 canSwipeToEnter == false ->
-                                    SceneKey.Gone to
+                                    Scenes.Gone to
                                         "device has been unlocked on lockscreen using an active" +
                                             " authentication mechanism"
                                 else -> null
@@ -281,7 +288,7 @@
             powerInteractor.isAsleep.collect { isAsleep ->
                 if (isAsleep) {
                     switchToScene(
-                        targetSceneKey = SceneKey.Lockscreen,
+                        targetSceneKey = Scenes.Lockscreen,
                         loggingReason = "device is starting to sleep",
                     )
                 } else {
@@ -289,7 +296,7 @@
                     val isUnlocked = deviceEntryInteractor.isUnlocked.value
                     if (isUnlocked && canSwipeToEnter == false) {
                         switchToScene(
-                            targetSceneKey = SceneKey.Gone,
+                            targetSceneKey = Scenes.Gone,
                             loggingReason =
                                 "device is waking up while unlocked without the ability" +
                                     " to swipe up on lockscreen to enter.",
@@ -299,7 +306,7 @@
                             AuthenticationMethodModel.Sim
                     ) {
                         switchToScene(
-                            targetSceneKey = SceneKey.Bouncer,
+                            targetSceneKey = Scenes.Bouncer,
                             loggingReason = "device is starting to wake up with a locked sim"
                         )
                     }
@@ -364,7 +371,7 @@
 
         applicationScope.launch {
             sceneInteractor.currentScene
-                .map { it == SceneKey.Bouncer }
+                .map { it == Scenes.Bouncer }
                 .distinctUntilChanged()
                 .collect { switchedToBouncerScene ->
                     if (switchedToBouncerScene) {
@@ -376,6 +383,18 @@
         }
     }
 
+    /** Switches to the lockscreen when falsing is detected. */
+    private fun respondToFalsingDetections() {
+        applicationScope.launch {
+            conflatedCallbackFlow {
+                    val listener = FalsingBeliefListener { trySend(Unit) }
+                    falsingManager.addFalsingBeliefListener(listener)
+                    awaitClose { falsingManager.removeFalsingBeliefListener(listener) }
+                }
+                .collect { switchToScene(Scenes.Lockscreen, "Falsing detected.") }
+        }
+    }
+
     /** Keeps the focus state of the window view up-to-date. */
     private fun hydrateWindowFocus() {
         applicationScope.launch {
@@ -385,7 +404,7 @@
                 }
                 .distinctUntilChanged()
                 .collect { sceneKey ->
-                    windowController.setNotificationShadeFocusable(sceneKey != SceneKey.Gone)
+                    windowController.setNotificationShadeFocusable(sceneKey != Scenes.Gone)
                 }
         }
     }
@@ -409,9 +428,9 @@
                                     //
                                     // This is done here in order to match the legacy
                                     // implementation. The real reason why is lost to lore and myth.
-                                    SceneKey.Lockscreen -> true
-                                    SceneKey.Bouncer -> false
-                                    SceneKey.Shade -> false
+                                    Scenes.Lockscreen -> true
+                                    Scenes.Bouncer -> false
+                                    Scenes.Shade -> false
                                     else -> null
                                 }
                             }
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
index 8408c51..1808d98 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
@@ -24,7 +24,6 @@
 import com.android.systemui.Flags.keyguardBottomAreaRefactor
 import com.android.systemui.Flags.migrateClocksToBlueprint
 import com.android.systemui.Flags.sceneContainer
-import com.android.systemui.compose.ComposeFacade
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.flags.FlagToken
 import com.android.systemui.flags.Flags.SCENE_CONTAINER_ENABLED
@@ -47,9 +46,8 @@
                 keyguardBottomAreaRefactor() &&
                 migrateClocksToBlueprint() &&
                 ComposeLockscreen.isEnabled &&
-                MediaInSceneContainerFlag.isEnabled &&
-                // NOTE: Changes should also be made in getSecondaryFlags and @EnableSceneContainer
-                ComposeFacade.isComposeAvailable()
+                MediaInSceneContainerFlag.isEnabled
+    // NOTE: Changes should also be made in getSecondaryFlags and @EnableSceneContainer
 
     /**
      * The main static flag, SCENE_CONTAINER_ENABLED. This is an explicit static flag check that
@@ -74,11 +72,7 @@
 
     /** The full set of requirements for SceneContainer */
     inline fun getAllRequirements(): Sequence<FlagToken> {
-        val composeRequirement =
-            FlagToken("ComposeFacade.isComposeAvailable()", ComposeFacade.isComposeAvailable())
-        return sequenceOf(getMainStaticFlag(), getMainAconfigFlag()) +
-            getSecondaryFlags() +
-            composeRequirement
+        return sequenceOf(getMainStaticFlag(), getMainAconfigFlag()) + getSecondaryFlags()
     }
 
     /** Return all dependencies of this flag in pairs where [Pair.first] depends on [Pair.second] */
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 d59fcff..f44779a 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
@@ -16,10 +16,10 @@
 
 package com.android.systemui.scene.shared.logger
 
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.LogLevel
 import com.android.systemui.log.dagger.SceneFrameworkLog
-import com.android.systemui.scene.shared.model.SceneKey
 import javax.inject.Inject
 
 class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer: LogBuffer) {
@@ -95,6 +95,26 @@
         )
     }
 
+    fun logRemoteUserInteractionStarted(
+        reason: String,
+    ) {
+        logBuffer.log(
+            tag = TAG,
+            level = LogLevel.INFO,
+            messageInitializer = { str1 = reason },
+            messagePrinter = { "remote user interaction started, reason: $str3" },
+        )
+    }
+
+    fun logUserInteractionFinished() {
+        logBuffer.log(
+            tag = TAG,
+            level = LogLevel.INFO,
+            messageInitializer = {},
+            messagePrinter = { "user interaction finished" },
+        )
+    }
+
     companion object {
         private const val TAG = "SceneFramework"
     }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt
deleted file mode 100644
index f704894..0000000
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt
+++ /dev/null
@@ -1,54 +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 kotlinx.coroutines.flow.Flow
-
-/**
- * This is a fork of a class by the same name in the `com.android.compose.animation.scene` package.
- *
- * TODO(b/293899074): remove this fork, once we can compile Compose into System UI.
- */
-sealed class ObservableTransitionState {
-    /** No transition/animation is currently running. */
-    data class Idle(val scene: SceneKey) : ObservableTransitionState()
-
-    /** There is a transition animating between two scenes. */
-    data class Transition(
-        val fromScene: SceneKey,
-        val toScene: SceneKey,
-        val progress: Flow<Float>,
-
-        /**
-         * Whether the transition was originally triggered by user input rather than being
-         * programmatic. If this value is initially true, it will remain true until the transition
-         * fully completes, even if the user input that triggered the transition has ended. Any
-         * sub-transitions launched by this one will inherit this value. For example, if the user
-         * drags a pointer but does not exceed the threshold required to transition to another
-         * scene, this value will remain true after the pointer is no longer touching the screen and
-         * will be true in any transition created to animate back to the original position.
-         */
-        val isInitiatedByUserInput: Boolean,
-
-        /**
-         * Whether user input is currently driving the transition. For example, if a user is
-         * dragging a pointer, this emits true. Once they lift their finger, this emits false while
-         * the transition completes/settles.
-         */
-        val isUserInputOngoing: Flow<Boolean>,
-    ) : ObservableTransitionState()
-}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt
index 05056c1..939d5bc 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt
@@ -16,6 +16,9 @@
 
 package com.android.systemui.scene.shared.model
 
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
 import kotlinx.coroutines.flow.StateFlow
 
 /**
@@ -53,39 +56,3 @@
      */
     val destinationScenes: StateFlow<Map<UserAction, UserActionResult>>
 }
-
-/** Enumerates all scene framework supported user actions. */
-sealed interface UserAction {
-
-    /** The user is scrolling, dragging, swiping, or flinging. */
-    data class Swipe(
-        /** The direction of the swipe. */
-        val direction: Direction,
-        /**
-         * The edge from which the swipe originated or `null`, if the swipe didn't start close to an
-         * edge.
-         */
-        val fromEdge: Edge? = null,
-        /** The number of pointers that were used (for example, one or two fingers). */
-        val pointerCount: Int = 1,
-    ) : UserAction
-
-    /** The user has hit the back button or performed the back navigation gesture. */
-    data object Back : UserAction
-}
-
-/** Enumerates all known "cardinal" directions for user actions. */
-enum class Direction {
-    LEFT,
-    UP,
-    RIGHT,
-    DOWN,
-}
-
-/** Enumerates all known edges from which a swipe can start. */
-enum class Edge {
-    LEFT,
-    TOP,
-    RIGHT,
-    BOTTOM,
-}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt
index 8204edc..53cdaaa 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.scene.shared.model
 
+import com.android.compose.animation.scene.SceneKey
+
 /** Models the configuration of the scene container. */
 data class SceneContainerConfig(
 
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt
index f7b45e5..0e078d5 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.scene.shared.model
 
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.TransitionKey
 import kotlinx.coroutines.flow.StateFlow
 
 /** Defines interface for classes that provide access to scene state. */
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt
index a50830c..69dce83 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt
@@ -18,6 +18,8 @@
 
 package com.android.systemui.scene.shared.model
 
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.TransitionKey
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneKey.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
similarity index 77%
rename from packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneKey.kt
rename to packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
index 609d2b9..73fcca8 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneKey.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
@@ -16,41 +16,37 @@
 
 package com.android.systemui.scene.shared.model
 
+import com.android.compose.animation.scene.SceneKey
+
 /**
  * Keys of all known scenes.
  *
  * PLEASE KEEP THE KEYS SORTED ALPHABETICALLY.
  */
-sealed class SceneKey(
-    private val loggingName: String,
-) {
+object Scenes {
     /**
      * The bouncer is the scene that displays authentication challenges like PIN, password, or
      * pattern.
      */
-    object Bouncer : SceneKey("bouncer")
+    @JvmField val Bouncer = SceneKey("bouncer")
 
     /** The communal scene shows the glanceable hub when device is locked and docked. */
-    object Communal : SceneKey("communal")
+    @JvmField val Communal = SceneKey("communal")
 
     /**
      * "Gone" is not a real scene but rather the absence of scenes when we want to skip showing any
      * content from the scene framework.
      */
-    object Gone : SceneKey("gone")
+    @JvmField val Gone = SceneKey("gone")
 
     /** The lockscreen is the scene that shows when the device is locked. */
-    object Lockscreen : SceneKey("lockscreen")
+    @JvmField val Lockscreen = SceneKey("lockscreen")
 
     /** The quick settings scene shows the quick setting tiles. */
-    object QuickSettings : SceneKey("quick_settings")
+    @JvmField val QuickSettings = SceneKey("quick_settings")
 
     /**
      * The shade is the scene whose primary purpose is to show a scrollable list of notifications.
      */
-    object Shade : SceneKey("shade")
-
-    override fun toString(): String {
-        return loggingName
-    }
+    @JvmField val Shade = SceneKey("shade")
 }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt
index 926878c..b91dd04 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.scene.shared.model
 
+import com.android.compose.animation.scene.TransitionKey
+
 /**
  * Defines all known named transitions.
  *
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/UserActionResult.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/UserActionResult.kt
deleted file mode 100644
index e1b96e4..0000000
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/UserActionResult.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.scene.shared.model
-
-data class UserActionResult(
-
-    /** The scene we should be transitioning due to the [UserAction]. */
-    val toScene: SceneKey,
-
-    /**
-     * The distance the action takes to animate from 0% to 100%.
-     *
-     * If `null`, a default distance will be used depending on the [UserAction] performed.
-     */
-    val distance: UserActionDistance? = null,
-
-    /**
-     * The key of the transition that should be used, if a specific one should be used.
-     *
-     * If `null`, the transition used will be the corresponding transition from the collection
-     * passed into the UI layer.
-     */
-    val transitionKey: TransitionKey? = null,
-)
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 45b6f65..7c31ca2 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
@@ -16,31 +16,43 @@
 
 package com.android.systemui.scene.ui.view
 
-import android.view.Gravity
+import android.content.Context
+import android.graphics.Point
 import android.view.View
 import android.view.ViewGroup
 import android.view.WindowInsets
-import android.widget.FrameLayout
 import androidx.activity.OnBackPressedDispatcher
 import androidx.activity.OnBackPressedDispatcherOwner
 import androidx.activity.setViewTreeOnBackPressedDispatcherOwner
+import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
 import androidx.core.view.isVisible
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.compose.ComposeFacade
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.theme.PlatformTheme
+import com.android.internal.policy.ScreenDecorationsUtils
+import com.android.systemui.common.ui.compose.windowinsets.CutoutLocation
+import com.android.systemui.common.ui.compose.windowinsets.DisplayCutout
+import com.android.systemui.common.ui.compose.windowinsets.ScreenDecorProvider
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.res.R
 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.shared.model.SceneDataSourceDelegator
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.ui.composable.ComposableScene
+import com.android.systemui.scene.ui.composable.SceneContainer
 import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
 import com.android.systemui.statusbar.notification.stack.shared.flexiNotifsEnabled
 import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
-import java.time.Instant
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.launch
 
 object SceneWindowRootViewBinder {
@@ -86,7 +98,7 @@
                     )
 
                     view.addView(
-                        ComposeFacade.createSceneContainerView(
+                        createSceneContainerView(
                                 scope = this,
                                 context = view.context,
                                 viewModel = viewModel,
@@ -98,7 +110,7 @@
                     )
 
                     val legacyView = view.requireViewById<View>(R.id.legacy_window_root)
-                    view.addView(createVisibilityToggleView(legacyView))
+                    legacyView.isVisible = false
 
                     // This moves the SharedNotificationContainer to the WindowRootView just after
                     //  the SceneContainerView. This SharedNotificationContainer should contain NSSL
@@ -124,28 +136,73 @@
         }
     }
 
-    private var clickCount = 0
-    private var lastClick = Instant.now()
-
-    /**
-     * A temporary UI to toggle on/off the visibility of the given [otherView]. It is toggled by
-     * tapping 5 times in quick succession on the device camera (top center).
-     */
-    // TODO(b/291321285): Remove this when the Flexiglass UI is mature enough to turn off legacy
-    //  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()
-            clickCount = if (now.minusSeconds(2) > lastClick) 1 else clickCount + 1
-            if (clickCount == 5) {
-                otherView.isVisible = !otherView.isVisible
-                clickCount = 0
+    private fun createSceneContainerView(
+        scope: CoroutineScope,
+        context: Context,
+        viewModel: SceneContainerViewModel,
+        windowInsets: StateFlow<WindowInsets?>,
+        sceneByKey: Map<SceneKey, Scene>,
+        dataSourceDelegator: SceneDataSourceDelegator,
+    ): View {
+        return ComposeView(context).apply {
+            setContent {
+                PlatformTheme {
+                    ScreenDecorProvider(
+                        displayCutout = displayCutoutFromWindowInsets(scope, context, windowInsets),
+                        screenCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
+                    ) {
+                        SceneContainer(
+                            viewModel = viewModel,
+                            sceneByKey =
+                                sceneByKey.mapValues { (_, scene) -> scene as ComposableScene },
+                            dataSourceDelegator = dataSourceDelegator,
+                        )
+                    }
+                }
             }
-            lastClick = now
         }
-        return toggleView
+    }
+
+    // TODO(b/298525212): remove once Compose exposes window inset bounds.
+    private fun displayCutoutFromWindowInsets(
+        scope: CoroutineScope,
+        context: Context,
+        windowInsets: StateFlow<WindowInsets?>,
+    ): StateFlow<DisplayCutout> =
+        windowInsets
+            .map {
+                val boundingRect = it?.displayCutout?.boundingRectTop
+                val width = boundingRect?.let { boundingRect.right - boundingRect.left } ?: 0
+                val left = boundingRect?.left?.toDp(context) ?: 0.dp
+                val top = boundingRect?.top?.toDp(context) ?: 0.dp
+                val right = boundingRect?.right?.toDp(context) ?: 0.dp
+                val bottom = boundingRect?.bottom?.toDp(context) ?: 0.dp
+                val location =
+                    when {
+                        width <= 0f -> CutoutLocation.NONE
+                        left <= 0.dp -> CutoutLocation.LEFT
+                        right >= getDisplayWidth(context) -> CutoutLocation.RIGHT
+                        else -> CutoutLocation.CENTER
+                    }
+                DisplayCutout(
+                    left,
+                    top,
+                    right,
+                    bottom,
+                    location,
+                )
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), DisplayCutout())
+
+    // TODO(b/298525212): remove once Compose exposes window inset bounds.
+    private fun getDisplayWidth(context: Context): Dp {
+        val point = Point()
+        checkNotNull(context.display).getRealSize(point)
+        return point.x.dp
+    }
+
+    // TODO(b/298525212): remove once Compose exposes window inset bounds.
+    private fun Int.toDp(context: Context): Dp {
+        return (this.toFloat() / context.resources.displayMetrics.density).dp
     }
 }
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 4c2c979..ea19020 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
@@ -25,7 +25,7 @@
 import android.view.WindowInsets
 import android.widget.FrameLayout
 import androidx.core.view.updateMargins
-import com.android.systemui.compose.ComposeFacade
+import com.android.systemui.compose.ComposeInitializer
 import com.android.systemui.res.R
 
 /** A view that can serve as the root of the main SysUI window. */
@@ -45,16 +45,16 @@
     override fun onAttachedToWindow() {
         super.onAttachedToWindow()
 
-        if (ComposeFacade.isComposeAvailable() && isRoot()) {
-            ComposeFacade.composeInitializer().onAttachedToWindow(this)
+        if (isRoot()) {
+            ComposeInitializer.onAttachedToWindow(this)
         }
     }
 
     override fun onDetachedFromWindow() {
         super.onDetachedFromWindow()
 
-        if (ComposeFacade.isComposeAvailable() && isRoot()) {
-            ComposeFacade.composeInitializer().onDetachedFromWindow(this)
+        if (isRoot()) {
+            ComposeInitializer.onDetachedFromWindow(this)
         }
     }
 
@@ -71,7 +71,6 @@
 
     override fun onApplyWindowInsets(windowInsets: WindowInsets): WindowInsets? {
         val insets = windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars())
-        val displayCutout = rootWindowInsets.displayCutout
         if (fitsSystemWindows) {
             val paddingChanged = insets.top != paddingTop || insets.bottom != paddingBottom
 
@@ -79,23 +78,22 @@
             if (paddingChanged) {
                 setPadding(0, 0, 0, 0)
             }
-
-            val pairInsets: Pair<Int, Int> =
-                layoutInsetsController.getinsets(windowInsets, displayCutout)
-            leftInset = pairInsets.first
-            rightInset = pairInsets.second
-            applyMargins()
         } else {
             val changed =
                 paddingLeft != 0 || paddingRight != 0 || paddingTop != 0 || paddingBottom != 0
             if (changed) {
                 setPadding(0, 0, 0, 0)
             }
-
-            leftInset = 0
-            rightInset = 0
         }
+        leftInset = 0
+        rightInset = 0
 
+        val displayCutout = rootWindowInsets.displayCutout
+        val pairInsets: Pair<Int, Int> =
+            layoutInsetsController.getinsets(windowInsets, displayCutout)
+        leftInset = pairInsets.first
+        rightInset = pairInsets.second
+        applyMargins()
         return windowInsets
     }
 
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 4cd3baa..231b284 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
@@ -17,13 +17,14 @@
 package com.android.systemui.scene.ui.viewmodel
 
 import android.view.MotionEvent
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.classifier.Classifier
 import com.android.systemui.classifier.domain.interactor.FalsingInteractor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.power.domain.interactor.PowerInteractor
 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.scene.shared.model.Scenes
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.StateFlow
@@ -68,6 +69,12 @@
     fun onMotionEvent(event: MotionEvent) {
         powerInteractor.onUserTouch()
         falsingInteractor.onTouchEvent(event)
+        if (
+            event.actionMasked == MotionEvent.ACTION_UP ||
+                event.actionMasked == MotionEvent.ACTION_CANCEL
+        ) {
+            sceneInteractor.onUserInteractionFinished()
+        }
     }
 
     /**
@@ -90,10 +97,10 @@
     fun canChangeScene(toScene: SceneKey): Boolean {
         val interactionTypeOrNull =
             when (toScene) {
-                SceneKey.Bouncer -> Classifier.BOUNCER_UNLOCK
-                SceneKey.Gone -> Classifier.UNLOCK
-                SceneKey.Shade -> Classifier.NOTIFICATION_DRAG_DOWN
-                SceneKey.QuickSettings -> Classifier.QUICK_SETTINGS
+                Scenes.Bouncer -> Classifier.BOUNCER_UNLOCK
+                Scenes.Gone -> Classifier.UNLOCK
+                Scenes.Shade -> Classifier.NOTIFICATION_DRAG_DOWN
+                Scenes.QuickSettings -> Classifier.QUICK_SETTINGS
                 else -> null
             }
 
@@ -103,7 +110,7 @@
             val isFalseTouch = falsingInteractor.isFalseTouch(interactionType)
 
             // Only enforce falsing if moving from the lockscreen scene to a new scene.
-            val fromLockscreenScene = currentScene.value == SceneKey.Lockscreen
+            val fromLockscreenScene = currentScene.value == Scenes.Lockscreen
 
             !fromLockscreenScene || !isFalseTouch
         }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
index fb5339d..1f9853b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.screenshot
 
+import android.app.ActivityOptions
+import android.app.ExitTransitionCoordinator
 import android.content.Context
 import android.content.Intent
 import android.os.Bundle
@@ -23,6 +25,7 @@
 import android.os.RemoteException
 import android.os.UserHandle
 import android.util.Log
+import android.util.Pair
 import android.view.IRemoteAnimationFinishedCallback
 import android.view.IRemoteAnimationRunner
 import android.view.RemoteAnimationAdapter
@@ -64,18 +67,18 @@
      */
     fun launchIntentAsync(
         intent: Intent,
-        options: Bundle?,
+        transition: Pair<ActivityOptions, ExitTransitionCoordinator>?,
         user: UserHandle,
         overrideTransition: Boolean,
     ) {
         applicationScope.launch("$TAG#launchIntentAsync") {
-            launchIntent(intent, options, user, overrideTransition)
+            launchIntent(intent, transition, user, overrideTransition)
         }
     }
 
     suspend fun launchIntent(
         intent: Intent,
-        options: Bundle?,
+        transition: Pair<ActivityOptions, ExitTransitionCoordinator>?,
         user: UserHandle,
         overrideTransition: Boolean,
     ) {
@@ -87,11 +90,14 @@
         } else {
             dismissKeyguard()
         }
+        transition?.second?.startExit()
 
         if (user == myUserHandle()) {
-            withContext(mainDispatcher) { context.startActivity(intent, options) }
+            withContext(mainDispatcher) {
+                context.startActivity(intent, transition?.first?.toBundle())
+            }
         } else {
-            launchCrossProfileIntent(user, intent, options)
+            launchCrossProfileIntent(user, intent, transition?.first?.toBundle())
         }
 
         if (overrideTransition) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java b/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java
index 0588fe2..30f5e8b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java
@@ -18,6 +18,7 @@
 
 import static java.util.Objects.requireNonNull;
 
+import android.app.ActivityOptions;
 import android.app.BroadcastOptions;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -100,7 +101,7 @@
                 BroadcastOptions options = BroadcastOptions.makeBasic();
                 options.setInteractive(true);
                 options.setPendingIntentBackgroundActivityStartMode(
-                        BroadcastOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+                        ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
                 intent.send(options.toBundle());
                 finisher.run();
             } catch (PendingIntent.CanceledException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index 31086d8..bbf7ed5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -16,40 +16,29 @@
 
 package com.android.systemui.screenshot;
 
-import static com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS;
 import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
 import static com.android.systemui.screenshot.LogConfig.DEBUG_STORAGE;
 import static com.android.systemui.screenshot.LogConfig.logTag;
 import static com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType;
 
-import android.app.ActivityTaskManager;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.ClipData;
 import android.content.ClipDescription;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Process;
-import android.os.RemoteException;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.provider.DeviceConfig;
-import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
-import com.android.systemui.res.R;
 import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -60,7 +49,6 @@
 import java.util.Random;
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
-import java.util.function.Supplier;
 
 /**
  * An AsyncTask that saves an image to the media store in the background.
@@ -81,7 +69,6 @@
     private final ScreenshotNotificationSmartActionsProvider mSmartActionsProvider;
     private String mScreenshotId;
     private final Random mRandom = new Random();
-    private final Supplier<ActionTransition> mSharedElementTransition;
     private final ImageExporter mImageExporter;
     private long mImageTime;
 
@@ -91,7 +78,6 @@
             ImageExporter exporter,
             ScreenshotSmartActions screenshotSmartActions,
             ScreenshotController.SaveImageInBackgroundData data,
-            Supplier<ActionTransition> sharedElementTransition,
             ScreenshotNotificationSmartActionsProvider
                     screenshotNotificationSmartActionsProvider
     ) {
@@ -100,7 +86,6 @@
         mScreenshotSmartActions = screenshotSmartActions;
         mImageData = new ScreenshotController.SavedImageData();
         mQuickShareData = new ScreenshotController.QuickShareData();
-        mSharedElementTransition = sharedElementTransition;
         mImageExporter = exporter;
 
         // Prepare all the output metadata
@@ -176,12 +161,6 @@
             mImageData.uri = uri;
             mImageData.owner = mParams.owner;
             mImageData.smartActions = smartActions;
-            mImageData.shareTransition = createShareAction(mContext, mContext.getResources(), uri,
-                    smartActionsEnabled);
-            mImageData.editTransition = createEditAction(mContext, mContext.getResources(), uri,
-                    smartActionsEnabled);
-            mImageData.deleteAction = createDeleteAction(mContext, mContext.getResources(), uri,
-                    smartActionsEnabled);
             mImageData.quickShareAction = createQuickShareAction(
                     mQuickShareData.quickShareAction, mScreenshotId, uri, mImageTime, image,
                     mParams.owner);
@@ -234,164 +213,6 @@
         mParams.clearImage();
     }
 
-    /**
-     * Assumes that the action intent is sent immediately after being supplied.
-     */
-    @VisibleForTesting
-    Supplier<ActionTransition> createShareAction(Context context, Resources r, Uri uri,
-            boolean smartActionsEnabled) {
-        return () -> {
-            ActionTransition transition = mSharedElementTransition.get();
-
-            // Note: Both the share and edit actions are proxied through ActionProxyReceiver in
-            // order to do some common work like dismissing the keyguard and sending
-            // closeSystemWindows
-
-            // Create a share intent, this will always go through the chooser activity first
-            // which should not trigger auto-enter PiP
-            Intent sharingIntent = new Intent(Intent.ACTION_SEND);
-            sharingIntent.setDataAndType(uri, "image/png");
-            sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
-            // Include URI in ClipData also, so that grantPermission picks it up.
-            // We don't use setData here because some apps interpret this as "to:".
-            ClipData clipdata = new ClipData(new ClipDescription("content",
-                    new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN}),
-                    new ClipData.Item(uri));
-            sharingIntent.setClipData(clipdata);
-            sharingIntent.putExtra(Intent.EXTRA_SUBJECT, getSubjectString(mImageTime));
-            sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
-                    .addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-
-
-            // Make sure pending intents for the system user are still unique across users
-            // by setting the (otherwise unused) request code to the current user id.
-            int requestCode = context.getUserId();
-
-            Intent sharingChooserIntent = Intent.createChooser(sharingIntent, null)
-                    .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK)
-                    .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
-
-            // cancel current pending intent (if any) since clipData isn't used for matching
-            PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
-                    context, 0, sharingChooserIntent,
-                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
-                    transition.bundle, UserHandle.CURRENT);
-
-            // Create a share action for the notification
-            PendingIntent shareAction = PendingIntent.getBroadcastAsUser(context, requestCode,
-                    new Intent(context, ActionProxyReceiver.class)
-                            .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, pendingIntent)
-                            .putExtra(ScreenshotController.EXTRA_DISALLOW_ENTER_PIP, true)
-                            .putExtra(ScreenshotController.EXTRA_ID, mScreenshotId)
-                            .putExtra(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED,
-                                    smartActionsEnabled)
-                            .setAction(Intent.ACTION_SEND)
-                            .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
-                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
-                    UserHandle.SYSTEM);
-
-            Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder(
-                    Icon.createWithResource(r, R.drawable.ic_screenshot_share),
-                    r.getString(com.android.internal.R.string.share), shareAction);
-
-            transition.action = shareActionBuilder.build();
-            return transition;
-        };
-    }
-
-    @VisibleForTesting
-    Supplier<ActionTransition> createEditAction(Context context, Resources r, Uri uri,
-            boolean smartActionsEnabled) {
-        return () -> {
-            ActionTransition transition = mSharedElementTransition.get();
-            // Note: Both the share and edit actions are proxied through ActionProxyReceiver in
-            // order to do some common work like dismissing the keyguard and sending
-            // closeSystemWindows
-
-            // Create an edit intent, if a specific package is provided as the editor, then
-            // launch that directly
-            String editorPackage = context.getString(R.string.config_screenshotEditor);
-            Intent editIntent = new Intent(Intent.ACTION_EDIT);
-            if (!TextUtils.isEmpty(editorPackage)) {
-                editIntent.setComponent(ComponentName.unflattenFromString(editorPackage));
-            }
-            editIntent.setDataAndType(uri, "image/png");
-            editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-            editIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-            editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-
-            PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
-                    context, 0, editIntent, PendingIntent.FLAG_IMMUTABLE,
-                    transition.bundle, UserHandle.CURRENT);
-
-            // Make sure pending intents for the system user are still unique across users
-            // by setting the (otherwise unused) request code to the current user id.
-            int requestCode = mContext.getUserId();
-
-            // Create an edit action
-            PendingIntent editAction = PendingIntent.getBroadcastAsUser(context, requestCode,
-                    new Intent(context, ActionProxyReceiver.class)
-                            .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, pendingIntent)
-                            .putExtra(ScreenshotController.EXTRA_ID, mScreenshotId)
-                            .putExtra(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED,
-                                    smartActionsEnabled)
-                            .putExtra(ScreenshotController.EXTRA_OVERRIDE_TRANSITION, true)
-                            .setAction(Intent.ACTION_EDIT)
-                            .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
-                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
-                    UserHandle.SYSTEM);
-            Notification.Action.Builder editActionBuilder = new Notification.Action.Builder(
-                    Icon.createWithResource(r, R.drawable.ic_screenshot_edit),
-                    r.getString(com.android.internal.R.string.screenshot_edit), editAction);
-
-            transition.action = editActionBuilder.build();
-            return transition;
-        };
-    }
-
-    @VisibleForTesting
-    Notification.Action createDeleteAction(Context context, Resources r, Uri uri,
-            boolean smartActionsEnabled) {
-        // Make sure pending intents for the system user are still unique across users
-        // by setting the (otherwise unused) request code to the current user id.
-        int requestCode = mContext.getUserId();
-
-        // Create a delete action for the notification
-        PendingIntent deleteAction = PendingIntent.getBroadcast(context, requestCode,
-                new Intent(context, DeleteScreenshotReceiver.class)
-                        .putExtra(ScreenshotController.SCREENSHOT_URI_ID, uri.toString())
-                        .putExtra(ScreenshotController.EXTRA_ID, mScreenshotId)
-                        .putExtra(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED,
-                                smartActionsEnabled)
-                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
-                PendingIntent.FLAG_CANCEL_CURRENT
-                        | PendingIntent.FLAG_ONE_SHOT
-                        | PendingIntent.FLAG_IMMUTABLE);
-        Notification.Action.Builder deleteActionBuilder = new Notification.Action.Builder(
-                Icon.createWithResource(r, R.drawable.ic_screenshot_delete),
-                r.getString(com.android.internal.R.string.delete), deleteAction);
-
-        return deleteActionBuilder.build();
-    }
-
-    private UserHandle getUserHandleOfForegroundApplication(Context context) {
-        UserManager manager = UserManager.get(context);
-        int result;
-        // This logic matches
-        // com.android.systemui.statusbar.phone.PhoneStatusBarPolicy#updateManagedProfile
-        try {
-            result = ActivityTaskManager.getService().getLastResumedActivityUserId();
-        } catch (RemoteException e) {
-            if (DEBUG_ACTIONS) {
-                Log.d(TAG, "Failed to get UserHandle of foreground app: ", e);
-            }
-            result = context.getUserId();
-        }
-        UserInfo userInfo = manager.getUserInfo(result);
-        return userInfo.getUserHandle();
-    }
-
     private List<Notification.Action> buildSmartActions(
             List<Notification.Action> actions, Context context) {
         List<Notification.Action> broadcastActions = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 21a08a9..ee3e7ba 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -39,7 +39,6 @@
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ExitTransitionCoordinator;
-import android.app.ExitTransitionCoordinator.ExitTransitionCallbacks;
 import android.app.ICompatCameraControlCallback;
 import android.app.Notification;
 import android.app.assist.AssistContent;
@@ -54,7 +53,6 @@
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
 import android.net.Uri;
-import android.os.Bundle;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -87,13 +85,12 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.policy.PhoneWindow;
 import com.android.settingslib.applications.InterestingConfigChanges;
-import com.android.systemui.res.R;
 import com.android.systemui.broadcast.BroadcastSender;
 import com.android.systemui.clipboardoverlay.ClipboardOverlayController;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
-import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
+import com.android.systemui.res.R;
 import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback;
 import com.android.systemui.util.Assert;
 
@@ -111,7 +108,6 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.function.Consumer;
-import java.util.function.Supplier;
 
 import javax.inject.Provider;
 
@@ -171,31 +167,16 @@
      */
     static class SavedImageData {
         public Uri uri;
-        public Supplier<ActionTransition> shareTransition;
-        public Supplier<ActionTransition> editTransition;
-        public Notification.Action deleteAction;
         public List<Notification.Action> smartActions;
         public Notification.Action quickShareAction;
         public UserHandle owner;
         public String subject;  // Title for sharing
 
         /**
-         * POD for shared element transition.
-         */
-        static class ActionTransition {
-            public Bundle bundle;
-            public Notification.Action action;
-            public Runnable onCancelRunnable;
-        }
-
-        /**
          * Used to reset the return data on error
          */
         public void reset() {
             uri = null;
-            shareTransition = null;
-            editTransition = null;
-            deleteAction = null;
             smartActions = null;
             quickShareAction = null;
             subject = null;
@@ -469,8 +450,9 @@
 
         if (!shouldShowUi()) {
             saveScreenshotInWorkerThread(
-                screenshot.getUserHandle(), finisher, this::logSuccessOnActionsReady,
-                (ignored) -> {});
+                    screenshot.getUserHandle(), finisher, this::logSuccessOnActionsReady,
+                    (ignored) -> {
+                    });
             return;
         }
 
@@ -489,7 +471,7 @@
         if (screenshot.getType() == WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE) {
             if (screenshot.getScreenBounds() != null
                     && aspectRatiosMatch(screenshot.getBitmap(), screenshot.getInsets(),
-                            screenshot.getScreenBounds())) {
+                    screenshot.getScreenBounds())) {
                 showFlash = false;
             } else {
                 showFlash = true;
@@ -643,6 +625,12 @@
             }
 
             @Override
+            public void onAction(Intent intent, UserHandle owner, boolean overrideTransition) {
+                mActionExecutor.launchIntentAsync(
+                        intent, createWindowTransition(), owner, overrideTransition);
+            }
+
+            @Override
             public void onDismiss() {
                 finishDismiss();
             }
@@ -652,7 +640,7 @@
                 // TODO(159460485): Remove this when focus is handled properly in the system
                 setWindowFocusable(false);
             }
-        }, mActionExecutor, mFlags);
+        }, mFlags);
         mScreenshotView.setDefaultDisplay(mDisplayId);
         mScreenshotView.setDefaultTimeoutMillis(mScreenshotHandler.getDefaultTimeoutMillis());
 
@@ -964,6 +952,35 @@
         mScreenshotAnimation.start();
     }
 
+    /**
+     * Supplies the necessary bits for the shared element transition to share sheet.
+     * Note that once called, the action intent to share must be sent immediately after.
+     */
+    private Pair<ActivityOptions, ExitTransitionCoordinator> createWindowTransition() {
+        ExitTransitionCoordinator.ExitTransitionCallbacks callbacks =
+                new ExitTransitionCoordinator.ExitTransitionCallbacks() {
+                    @Override
+                    public boolean isReturnTransitionAllowed() {
+                        return false;
+                    }
+
+                    @Override
+                    public void hideSharedElements() {
+                        finishDismiss();
+                    }
+
+                    @Override
+                    public void onFinish() {
+                    }
+                };
+        Pair<ActivityOptions, ExitTransitionCoordinator> transition =
+                ActivityOptions.startSharedElementAnimation(mWindow, callbacks, null,
+                        Pair.create(mScreenshotView.getScreenshotPreview(),
+                                ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME));
+
+        return transition;
+    }
+
     /** Reset screenshot view and then call onCompleteRunnable */
     private void finishDismiss() {
         Log.d(TAG, "finishDismiss");
@@ -1011,7 +1028,7 @@
         }
 
         mSaveInBgTask = new SaveImageInBackgroundTask(mContext, mFlags, mImageExporter,
-                mScreenshotSmartActions, data, getActionTransitionSupplier(),
+                mScreenshotSmartActions, data,
                 mScreenshotNotificationSmartActionsProvider);
         mSaveInBgTask.execute();
     }
@@ -1078,26 +1095,6 @@
     }
 
     /**
-     * Supplies the necessary bits for the shared element transition to share sheet.
-     * Note that once supplied, the action intent to share must be sent immediately after.
-     */
-    private Supplier<ActionTransition> getActionTransitionSupplier() {
-        return () -> {
-            Pair<ActivityOptions, ExitTransitionCoordinator> transition =
-                    ActivityOptions.startSharedElementAnimation(
-                            mWindow, new ScreenshotExitTransitionCallbacksSupplier(true).get(),
-                            null, Pair.create(mScreenshotView.getScreenshotPreview(),
-                                    ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME));
-            transition.second.startExit();
-
-            ActionTransition supply = new ActionTransition();
-            supply.bundle = transition.first.toBundle();
-            supply.onCancelRunnable = () -> ActivityOptions.stopSharedElementAnimation(mWindow);
-            return supply;
-        };
-    }
-
-    /**
      * Logs success/failure of the screenshot saving task, and shows an error if it failed.
      */
     private void logSuccessOnActionsReady(ScreenshotController.SavedImageData imageData) {
@@ -1186,36 +1183,6 @@
         return matchWithinTolerance;
     }
 
-    private class ScreenshotExitTransitionCallbacksSupplier implements
-            Supplier<ExitTransitionCallbacks> {
-        final boolean mDismissOnHideSharedElements;
-
-        ScreenshotExitTransitionCallbacksSupplier(boolean dismissOnHideSharedElements) {
-            mDismissOnHideSharedElements = dismissOnHideSharedElements;
-        }
-
-        @Override
-        public ExitTransitionCallbacks get() {
-            return new ExitTransitionCallbacks() {
-                @Override
-                public boolean isReturnTransitionAllowed() {
-                    return false;
-                }
-
-                @Override
-                public void hideSharedElements() {
-                    if (mDismissOnHideSharedElements) {
-                        finishDismiss();
-                    }
-                }
-
-                @Override
-                public void onFinish() {
-                }
-            };
-        }
-    }
-
     /** Injectable factory to create screenshot controller instances for a specific display. */
     @AssistedFactory
     public interface Factory {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 31c9284..be30a15 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -57,6 +57,7 @@
 import android.os.Bundle;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -86,9 +87,9 @@
 
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.res.R;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
+import com.android.systemui.res.R;
 import com.android.systemui.shared.system.InputChannelCompat;
 import com.android.systemui.shared.system.InputMonitorCompat;
 import com.android.systemui.shared.system.QuickStepContract;
@@ -104,6 +105,8 @@
     interface ScreenshotViewCallback {
         void onUserInteraction();
 
+        void onAction(Intent intent, UserHandle owner, boolean overrideTransition);
+
         void onDismiss();
 
         /** DOWN motion event was observed outside of the touchable areas of this view. */
@@ -166,7 +169,6 @@
 
     private final InteractionJankMonitor mInteractionJankMonitor;
     private long mDefaultTimeoutOfTimeoutHandler;
-    private ActionIntentExecutor mActionExecutor;
     private FeatureFlags mFlags;
     private final Bundle mInteractiveBroadcastOption;
 
@@ -430,11 +432,9 @@
      * Note: must be called before any other (non-constructor) method or null pointer exceptions
      * may occur.
      */
-    void init(UiEventLogger uiEventLogger, ScreenshotViewCallback callbacks,
-            ActionIntentExecutor actionExecutor, FeatureFlags flags) {
+    void init(UiEventLogger uiEventLogger, ScreenshotViewCallback callbacks, FeatureFlags flags) {
         mUiEventLogger = uiEventLogger;
         mCallbacks = callbacks;
-        mActionExecutor = actionExecutor;
         mFlags = flags;
     }
 
@@ -800,24 +800,21 @@
                 shareIntent = ActionIntentCreator.INSTANCE.createShareWithSubject(
                         imageData.uri, imageData.subject);
             }
-            mActionExecutor.launchIntentAsync(shareIntent,
-                    imageData.shareTransition.get().bundle,
-                    imageData.owner, false);
+            mCallbacks.onAction(shareIntent, imageData.owner, false);
+
         });
         mEditChip.setOnClickListener(v -> {
             mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED, 0, mPackageName);
             prepareSharedTransition();
-            mActionExecutor.launchIntentAsync(
+            mCallbacks.onAction(
                     ActionIntentCreator.INSTANCE.createEdit(imageData.uri, mContext),
-                    imageData.editTransition.get().bundle,
                     imageData.owner, true);
         });
         mScreenshotPreview.setOnClickListener(v -> {
             mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED, 0, mPackageName);
             prepareSharedTransition();
-            mActionExecutor.launchIntentAsync(
+            mCallbacks.onAction(
                     ActionIntentCreator.INSTANCE.createEdit(imageData.uri, mContext),
-                    imageData.editTransition.get().bundle,
                     imageData.owner, true);
         });
         if (mQuickShareChip != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
index 125f7fc..0a1f649 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -227,22 +227,10 @@
     protected open fun handleBeforeUserSwitching(newUserId: Int) {
         setUserIdInternal(newUserId)
 
-        val list = synchronized(callbacks) {
-            callbacks.toList()
-        }
-        val latch = CountDownLatch(list.size)
-        list.forEach {
-            val callback = it.callback.get()
-            if (callback != null) {
-                it.executor.execute {
-                    callback.onBeforeUserSwitching(newUserId)
-                    latch.countDown()
-                }
-            } else {
-                latch.countDown()
-            }
-        }
-        latch.await()
+        notifySubscribers { callback, resultCallback ->
+            callback.onBeforeUserSwitching(newUserId)
+            resultCallback.run()
+        }.await()
     }
 
     @WorkerThread
@@ -250,21 +238,9 @@
         Assert.isNotMainThread()
         Log.i(TAG, "Switching to user $newUserId")
 
-        val list = synchronized(callbacks) {
-            callbacks.toList()
-        }
-        val latch = CountDownLatch(list.size)
-        list.forEach {
-            val callback = it.callback.get()
-            if (callback != null) {
-                it.executor.execute {
-                    callback.onUserChanging(userId, userContext) { latch.countDown() }
-                }
-            } else {
-                latch.countDown()
-            }
-        }
-        latch.await()
+        notifySubscribers { callback, resultCallback ->
+            callback.onUserChanging(newUserId, userContext, resultCallback)
+        }.await()
     }
 
     @WorkerThread
@@ -294,9 +270,9 @@
         Assert.isNotMainThread()
         Log.i(TAG, "Switched to user $newUserId")
 
-        notifySubscribers {
-            onUserChanged(newUserId, userContext)
-            onProfilesChanged(userProfiles)
+        notifySubscribers { callback, _ ->
+            callback.onUserChanged(newUserId, userContext)
+            callback.onProfilesChanged(userProfiles)
         }
     }
 
@@ -308,8 +284,8 @@
         synchronized(mutex) {
             userProfiles = profiles.map { UserInfo(it) } // save a "deep" copy
         }
-        notifySubscribers {
-            onProfilesChanged(profiles)
+        notifySubscribers { callback, _ ->
+            callback.onProfilesChanged(profiles)
         }
     }
 
@@ -325,18 +301,24 @@
         }
     }
 
-    private inline fun notifySubscribers(crossinline action: UserTracker.Callback.() -> Unit) {
+    private inline fun notifySubscribers(
+            crossinline action: (UserTracker.Callback, resultCallback: Runnable) -> Unit
+    ): CountDownLatch {
         val list = synchronized(callbacks) {
             callbacks.toList()
         }
-
+        val latch = CountDownLatch(list.size)
         list.forEach {
-            if (it.callback.get() != null) {
+            val callback = it.callback.get()
+            if (callback != null) {
                 it.executor.execute {
-                    it.callback.get()?.action()
+                    action(callback) { latch.countDown() }
                 }
+            } else {
+                latch.countDown()
             }
         }
+        return latch
     }
 
     override fun dump(pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
index 6af9b73..e92630f 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
@@ -55,15 +55,15 @@
 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
 import com.android.systemui.util.settings.SecureSettings;
 
-import java.util.concurrent.Executor;
-
 import dagger.assisted.Assisted;
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
 
+import java.util.concurrent.Executor;
+
 public class BrightnessController implements ToggleSlider.Listener, MirroredBrightnessController {
     private static final String TAG = "CentralSurfaces.BrightnessController";
-    private static final int SLIDER_ANIMATION_DURATION = 3000;
+    private static final int SLIDER_ANIMATION_DURATION = 1000;
 
     private static final int MSG_UPDATE_SLIDER = 1;
     private static final int MSG_ATTACH_LISTENER = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
index df845f5..d3869ba 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
@@ -23,11 +23,12 @@
 import android.view.MotionEvent
 import android.view.View
 import android.view.ViewGroup
+import androidx.compose.ui.platform.ComposeView
+import com.android.compose.theme.PlatformTheme
 import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
+import com.android.systemui.communal.ui.compose.CommunalContainer
 import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
-import com.android.systemui.compose.ComposeFacade.createCommunalContainer
-import com.android.systemui.compose.ComposeFacade.isComposeAvailable
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.res.R
@@ -35,7 +36,6 @@
 import com.android.systemui.util.kotlin.collectFlow
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flowOf
 
 /**
  * Controller that's responsible for the glanceable hub container view and its touch handling.
@@ -107,8 +107,7 @@
     private var shadeShowing = false
 
     /** Returns a flow that tracks whether communal hub is available. */
-    fun communalAvailable(): Flow<Boolean> =
-        if (isComposeAvailable()) communalInteractor.isCommunalAvailable else flowOf(false)
+    fun communalAvailable(): Flow<Boolean> = communalInteractor.isCommunalAvailable
 
     /**
      * Creates the container view containing the glanceable hub UI.
@@ -118,7 +117,11 @@
     fun initView(
         context: Context,
     ): View {
-        return initView(createCommunalContainer(context, communalViewModel))
+        return initView(
+            ComposeView(context).apply {
+                setContent { PlatformTheme { CommunalContainer(viewModel = communalViewModel) } }
+            }
+        )
     }
 
     /** Override for testing. */
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 7068f5f..1566de5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -111,8 +111,6 @@
 import com.android.systemui.DejankUtils;
 import com.android.systemui.Dumpable;
 import com.android.systemui.Gefingerpoken;
-import com.android.systemui.animation.ActivityTransitionAnimator;
-import com.android.systemui.animation.TransitionAnimator;
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
 import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
@@ -219,7 +217,6 @@
 import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
 import com.android.systemui.statusbar.phone.TapAgainViewController;
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
-import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
@@ -259,10 +256,6 @@
     private static final boolean DEBUG_DRAWABLE = false;
     /** The parallax amount of the quick settings translation when dragging down the panel. */
     public static final float QS_PARALLAX_AMOUNT = 0.175f;
-    private static final long ANIMATION_DELAY_ICON_FADE_IN =
-            ActivityTransitionAnimator.TIMINGS.getTotalDuration()
-                    - CollapsedStatusBarFragment.FADE_IN_DURATION
-                    - CollapsedStatusBarFragment.FADE_IN_DELAY - 48;
     private static final int NO_FIXED_DURATION = -1;
     private static final long SHADE_OPEN_SPRING_OUT_DURATION = 350L;
     private static final long SHADE_OPEN_SPRING_BACK_DURATION = 400L;
@@ -463,7 +456,6 @@
      */
     private float mLinearDarkAmount;
     private boolean mPulsing;
-    private boolean mHideIconsDuringLaunchAnimation = true;
     private int mStackScrollerMeasuringPass;
     /** Non-null if a heads-up notification's position is being tracked. */
     @Nullable
@@ -1201,7 +1193,12 @@
         // Primary bouncer->Gone (ensures lockscreen content is not visible on successful auth)
         if (!migrateClocksToBlueprint()) {
             collectFlow(mView, mPrimaryBouncerToGoneTransitionViewModel.getLockscreenAlpha(),
-                    setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
+                    setTransitionAlpha(mNotificationStackScrollLayoutController,
+                            /* excludeNotifications=*/ true), mMainDispatcher);
+            collectFlow(mView, mPrimaryBouncerToGoneTransitionViewModel.getNotificationAlpha(),
+                    (Float alpha) -> {
+                        mNotificationStackScrollLayoutController.setMaxAlphaForExpansion(alpha);
+                    }, mMainDispatcher);
         }
     }
 
@@ -1539,6 +1536,7 @@
 
     @Override
     public void setOpenCloseListener(OpenCloseListener openCloseListener) {
+        SceneContainerFlag.assertInLegacyMode();
         mOpenCloseListener = openCloseListener;
     }
 
@@ -2047,7 +2045,6 @@
         mView.animate().cancel();
     }
 
-    @Override
     public void expandToQs() {
         if (mQsController.isExpansionEnabled()) {
             mQsController.setExpandImmediate(true);
@@ -2814,7 +2811,6 @@
         mQsController.setListening(listening);
     }
 
-    @Override
     public void expand(boolean animate) {
         if (isFullyCollapsed() || isCollapsing()) {
             mInstantExpanding = true;
@@ -3068,7 +3064,9 @@
     }
 
     private void onClosingFinished() {
-        mOpenCloseListener.onClosingFinished();
+        if (mOpenCloseListener != null) {
+            mOpenCloseListener.onClosingFinished();
+        }
         setClosingWithAlphaFadeout(false);
         mMediaHierarchyManager.closeGuts();
     }
@@ -3151,10 +3149,9 @@
         return mUnlockedScreenOffAnimationController.isAnimationPlaying();
     }
 
-    @Override
     public boolean shouldHideStatusBarIconsWhenExpanded() {
         if (isLaunchingActivity()) {
-            return mHideIconsDuringLaunchAnimation;
+            return false;
         }
         if (mHeadsUpAppearanceController != null
                 && mHeadsUpAppearanceController.shouldBeVisible()) {
@@ -3252,18 +3249,6 @@
     }
 
     @Override
-    public void applyLaunchAnimationProgress(float linearProgress) {
-        boolean hideIcons = TransitionAnimator.getProgress(ActivityTransitionAnimator.TIMINGS,
-                linearProgress, ANIMATION_DELAY_ICON_FADE_IN, 100) == 0.0f;
-        if (hideIcons != mHideIconsDuringLaunchAnimation) {
-            mHideIconsDuringLaunchAnimation = hideIcons;
-            if (!hideIcons) {
-                mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
-            }
-        }
-    }
-
-    @Override
     public void performHapticFeedback(int constant) {
         mVibratorHelper.performHapticFeedback(mView, constant);
     }
@@ -3465,7 +3450,6 @@
         ipw.print("mInterpolatedDarkAmount="); ipw.println(mInterpolatedDarkAmount);
         ipw.print("mLinearDarkAmount="); ipw.println(mLinearDarkAmount);
         ipw.print("mPulsing="); ipw.println(mPulsing);
-        ipw.print("mHideIconsDuringLaunchAnimation="); ipw.println(mHideIconsDuringLaunchAnimation);
         ipw.print("mStackScrollerMeasuringPass="); ipw.println(mStackScrollerMeasuringPass);
         ipw.print("mPanelAlpha="); ipw.println(mPanelAlpha);
         ipw.print("mBottomAreaShadeAlpha="); ipw.println(mBottomAreaShadeAlpha);
@@ -4157,7 +4141,6 @@
         return mShadeRepository.getLegacyIsClosing().getValue();
     }
 
-    @Override
     public void collapseWithDuration(int animationDuration) {
         mFixedDuration = animationDuration;
         collapse(false /* delayed */, 1.0f /* speedUpFactor */);
@@ -4699,7 +4682,9 @@
             if (mSplitShadeEnabled && !isKeyguardShowing()) {
                 mQsController.setExpandImmediate(true);
             }
-            mOpenCloseListener.onOpenStarted();
+            if (mOpenCloseListener != null) {
+                mOpenCloseListener.onOpenStarted();
+            }
         }
         if (state == STATE_CLOSED) {
             mQsController.setExpandImmediate(false);
@@ -4724,9 +4709,17 @@
 
     private Consumer<Float> setTransitionAlpha(
             NotificationStackScrollLayoutController stackScroller) {
+        return setTransitionAlpha(stackScroller, /* excludeNotifications= */ false);
+    }
+
+    private Consumer<Float> setTransitionAlpha(
+            NotificationStackScrollLayoutController stackScroller,
+            boolean excludeNotifications) {
         return (Float alpha) -> {
             mKeyguardStatusViewController.setAlpha(alpha);
-            stackScroller.setMaxAlphaForExpansion(alpha);
+            if (!excludeNotifications) {
+                stackScroller.setMaxAlphaForExpansion(alpha);
+            }
 
             if (keyguardBottomAreaRefactor()) {
                 mKeyguardInteractor.setAlpha(alpha);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index 8f9cef3..f7fed53 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -60,7 +60,6 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.res.R;
-import com.android.systemui.scene.shared.flag.SceneContainerFlag;
 import com.android.systemui.scene.shared.flag.SceneContainerFlags;
 import com.android.systemui.scene.ui.view.WindowRootViewComponent;
 import com.android.systemui.settings.UserTracker;
@@ -507,7 +506,7 @@
 
     private void applyFitsSystemWindows(NotificationShadeWindowState state) {
         boolean fitsSystemWindows = !state.isKeyguardShowingAndNotOccluded();
-        if (!SceneContainerFlag.isEnabled() && mWindowRootView != null
+        if (mWindowRootView != null
                 && mWindowRootView.getFitsSystemWindows() != fitsSystemWindows) {
             mWindowRootView.setFitsSystemWindows(fitsSystemWindows);
             mWindowRootView.requestApplyInsets();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index e7f9700..a5c0553 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -282,12 +282,6 @@
     /** The duration of the notification bounds animation. */
     private long mNotificationBoundsAnimationDuration;
 
-    /** TODO(b/273591201): remove after bug resolved */
-    private int mLastClippingTopBound;
-    private int mLastNotificationsTopPadding;
-    private int mLastNotificationsClippingTopBound;
-    private int mLastNotificationsClippingTopBoundNssl;
-
     private final Region mInterceptRegion = new Region();
     /** The end bounds of a clipping animation. */
     private final Rect mClippingAnimationEndBounds = new Rect();
@@ -2141,14 +2135,6 @@
         ipw.println(mNotificationBoundsAnimationDelay);
         ipw.print("mNotificationBoundsAnimationDuration=");
         ipw.println(mNotificationBoundsAnimationDuration);
-        ipw.print("mLastClippingTopBound=");
-        ipw.println(mLastClippingTopBound);
-        ipw.print("mLastNotificationsTopPadding=");
-        ipw.println(mLastNotificationsTopPadding);
-        ipw.print("mLastNotificationsClippingTopBound=");
-        ipw.println(mLastNotificationsClippingTopBound);
-        ipw.print("mLastNotificationsClippingTopBoundNssl=");
-        ipw.println(mLastNotificationsClippingTopBoundNssl);
         ipw.print("mInterceptRegion=");
         ipw.println(mInterceptRegion);
         ipw.print("mClippingAnimationEndBounds=");
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
index ec4b23a..0a57b64 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
@@ -78,6 +78,14 @@
      */
     void animateCollapseShade(int flags, boolean force, boolean delayed, float speedUpFactor);
 
+    /**
+     * Collapses the shade with an animation duration in milliseconds.
+     *
+     * @deprecated use animateCollapseShade with a speed up factor instead
+     */
+    @Deprecated
+    void collapseWithDuration(int animationDuration);
+
     /** Expand the shade with an animation. */
     void animateExpandShade();
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerEmptyImpl.kt
index 08a0c93..093690f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerEmptyImpl.kt
@@ -33,6 +33,7 @@
         delayed: Boolean,
         speedUpFactor: Float
     ) {}
+    override fun collapseWithDuration(animationDuration: Int) {}
     override fun animateExpandShade() {}
     override fun animateExpandQs() {}
     override fun postAnimateCollapseShade() {}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index ea41912..d99d607 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -32,6 +32,7 @@
 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.scene.shared.flag.SceneContainerFlag;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.StatusBarState;
@@ -98,6 +99,7 @@
                 statusBarKeyguardViewManager,
                 notificationShadeWindowController,
                 assistManagerLazy);
+        SceneContainerFlag.assertInLegacyMode();
         mCommandQueue = commandQueue;
         mMainExecutor = mainExecutor;
         mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor;
@@ -145,6 +147,11 @@
     }
 
     @Override
+    public void collapseWithDuration(int animationDuration) {
+        mNpvc.get().collapseWithDuration(animationDuration);
+    }
+
+    @Override
     protected void expandToNotifications() {
         getNpvc().expandToNotifications();
     }
@@ -219,7 +226,6 @@
         }
     }
 
-
     @Override
     public void collapseShade(boolean animate) {
         if (animate) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
index 6a2a6a4..27168a7 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.shade
 
 import android.view.MotionEvent
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.assist.AssistManager
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
@@ -25,7 +26,7 @@
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.dagger.ShadeTouchLog
 import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.shared.model.TransitionKeys.CollapseShadeInstantly
 import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse
 import com.android.systemui.shade.ShadeController.ShadeVisibilityListener
@@ -96,7 +97,7 @@
     }
 
     override fun instantCollapseShade() {
-        // TODO(b/315921512) add support for instant transition
+        // TODO(b/325602936) add support for instant transition
         sceneInteractor.changeScene(
             getCollapseDestinationScene(),
             "hide shade",
@@ -121,7 +122,7 @@
             // release focus immediately to kick off focus change transition
             notificationShadeWindowController.setNotificationShadeFocusable(false)
             notificationStackScrollLayout.cancelExpandHelper()
-            sceneInteractor.changeScene(SceneKey.Shade, "ShadeController.animateExpandShade")
+            sceneInteractor.changeScene(Scenes.Shade, "ShadeController.animateExpandShade")
             if (delayed) {
                 scope.launch {
                     delay(125)
@@ -133,6 +134,11 @@
         }
     }
 
+    override fun collapseWithDuration(animationDuration: Int) {
+        // TODO(b/300258424) inline this. The only caller uses the default duration.
+        animateCollapseShade()
+    }
+
     private fun animateCollapseShadeInternal() {
         sceneInteractor.changeScene(
             getCollapseDestinationScene(),
@@ -143,9 +149,9 @@
 
     private fun getCollapseDestinationScene(): SceneKey {
         return if (deviceEntryInteractor.isDeviceEntered.value) {
-            SceneKey.Gone
+            Scenes.Gone
         } else {
-            SceneKey.Lockscreen
+            Scenes.Lockscreen
         }
     }
 
@@ -183,11 +189,11 @@
     }
 
     override fun expandToNotifications() {
-        sceneInteractor.changeScene(SceneKey.Shade, "ShadeController.animateExpandShade")
+        sceneInteractor.changeScene(Scenes.Shade, "ShadeController.animateExpandShade")
     }
 
     override fun expandToQs() {
-        sceneInteractor.changeScene(SceneKey.QuickSettings, "ShadeController.animateExpandQs")
+        sceneInteractor.changeScene(Scenes.QuickSettings, "ShadeController.animateExpandQs")
     }
 
     override fun setVisibilityListener(listener: ShadeVisibilityListener) {
@@ -237,7 +243,7 @@
     }
 
     override fun isExpandedVisible(): Boolean {
-        return sceneInteractor.currentScene.value != SceneKey.Gone
+        return sceneInteractor.currentScene.value != Scenes.Gone
     }
 
     override fun onStatusBarTouch(event: MotionEvent) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index 44c6a82..7a1637e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -31,12 +31,6 @@
  * @see NotificationPanelViewController
  */
 interface ShadeViewController {
-    /** Expand the shade either animated or instantly. */
-    fun expand(animate: Boolean)
-
-    /** Animates to an expanded shade with QS expanded. If the shade starts expanded, expands QS. */
-    fun expandToQs()
-
     /** Returns whether the shade is expanding or collapsing itself or quick settings. */
     val isExpandingOrCollapsing: Boolean
 
@@ -58,9 +52,6 @@
     /** Collapses the shade. */
     fun collapse(animate: Boolean, delayed: Boolean, speedUpFactor: Float)
 
-    /** Collapses the shade with an animation duration in milliseconds. */
-    fun collapseWithDuration(animationDuration: Int)
-
     /** Collapses the shade instantly without animation. */
     fun instantCollapse()
 
@@ -102,9 +93,6 @@
     /** Returns the StatusBarState. */
     val barState: Int
 
-    /** Sets the amount of progress in the status bar launch animation. */
-    fun applyLaunchAnimationProgress(linearProgress: Float)
-
     /** Sets the alpha value of the shade to a value between 0 and 255. */
     fun setAlpha(alpha: Int, animate: Boolean)
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
index 7a181f1..3be3f6b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
@@ -28,8 +28,6 @@
 /** Empty implementation of ShadeViewController for variants with no shade. */
 class ShadeViewControllerEmptyImpl @Inject constructor() :
     ShadeViewController, ShadeBackActionInteractor, ShadeLockscreenInteractor {
-    override fun expand(animate: Boolean) {}
-    override fun expandToQs() {}
     override fun expandToNotifications() {}
     override val isExpandingOrCollapsing: Boolean = false
     override val isExpanded: Boolean = false
@@ -37,7 +35,6 @@
     override val isShadeFullyExpanded: Boolean = false
     override fun collapse(delayed: Boolean, speedUpFactor: Float) {}
     override fun collapse(animate: Boolean, delayed: Boolean, speedUpFactor: Float) {}
-    override fun collapseWithDuration(animationDuration: Int) {}
     override fun instantCollapse() {}
     override fun animateCollapseQs(fullyCollapse: Boolean) {}
     override fun canBeCollapsed(): Boolean = false
@@ -55,7 +52,6 @@
     override fun dozeTimeTick() {}
     override fun resetViews(animate: Boolean) {}
     override val barState: Int = 0
-    override fun applyLaunchAnimationProgress(linearProgress: Float) {}
     override fun closeUserSwitcherIfOpen(): Boolean {
         return false
     }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImpl.kt
index 1ee6d38..eaac8ae 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImpl.kt
@@ -16,10 +16,10 @@
 
 package com.android.systemui.shade.domain.interactor
 
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.dagger.SysUISingleton
 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.scene.shared.model.Scenes
 import com.android.systemui.shade.data.repository.ShadeAnimationRepository
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -44,10 +44,10 @@
                     is ObservableTransitionState.Idle -> flowOf(false)
                     is ObservableTransitionState.Transition ->
                         if (
-                            (state.fromScene == SceneKey.Shade &&
-                                state.toScene != SceneKey.QuickSettings) ||
-                                (state.fromScene == SceneKey.QuickSettings &&
-                                    state.toScene != SceneKey.Shade)
+                            (state.fromScene == Scenes.Shade &&
+                                state.toScene != Scenes.QuickSettings) ||
+                                (state.fromScene == Scenes.QuickSettings &&
+                                    state.toScene != Scenes.Shade)
                         ) {
                             state.isUserInputOngoing.map { !it }
                         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt
index a2e2598..3a8ba7a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt
@@ -18,7 +18,7 @@
 
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
 import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
@@ -36,12 +36,12 @@
             val key =
                 if (fullyCollapse) {
                     if (deviceEntryInteractor.isDeviceEntered.value) {
-                        SceneKey.Gone
+                        Scenes.Gone
                     } else {
-                        SceneKey.Lockscreen
+                        Scenes.Lockscreen
                     }
                 } else {
-                    SceneKey.Shade
+                    Scenes.Shade
                 }
             sceneInteractor.changeScene(key, "animateCollapseQs")
         }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
index 08f2c40..67cac3d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
@@ -16,11 +16,12 @@
 
 package com.android.systemui.shade.domain.interactor
 
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 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.scene.shared.model.Scenes
 import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -45,9 +46,9 @@
     sceneInteractor: SceneInteractor,
     sharedNotificationContainerInteractor: SharedNotificationContainerInteractor,
 ) : BaseShadeInteractor {
-    override val shadeExpansion: Flow<Float> = sceneBasedExpansion(sceneInteractor, SceneKey.Shade)
+    override val shadeExpansion: Flow<Float> = sceneBasedExpansion(sceneInteractor, Scenes.Shade)
 
-    private val sceneBasedQsExpansion = sceneBasedExpansion(sceneInteractor, SceneKey.QuickSettings)
+    private val sceneBasedQsExpansion = sceneBasedExpansion(sceneInteractor, Scenes.QuickSettings)
 
     override val qsExpansion: StateFlow<Float> =
         combine(
@@ -75,7 +76,7 @@
                 when (state) {
                     is ObservableTransitionState.Idle -> false
                     is ObservableTransitionState.Transition ->
-                        state.toScene == SceneKey.QuickSettings && state.fromScene != SceneKey.Shade
+                        state.toScene == Scenes.QuickSettings && state.fromScene != Scenes.Shade
                 }
             }
             .distinctUntilChanged()
@@ -84,7 +85,7 @@
         sceneInteractor.transitionState
             .map { state ->
                 when (state) {
-                    is ObservableTransitionState.Idle -> state.scene == SceneKey.QuickSettings
+                    is ObservableTransitionState.Idle -> state.scene == Scenes.QuickSettings
                     is ObservableTransitionState.Transition -> false
                 }
             }
@@ -100,10 +101,10 @@
             .stateIn(scope, SharingStarted.Eagerly, false)
 
     override val isUserInteractingWithShade: Flow<Boolean> =
-        sceneBasedInteracting(sceneInteractor, SceneKey.Shade)
+        sceneBasedInteracting(sceneInteractor, Scenes.Shade)
 
     override val isUserInteractingWithQs: Flow<Boolean> =
-        sceneBasedInteracting(sceneInteractor, SceneKey.QuickSettings)
+        sceneBasedInteracting(sceneInteractor, Scenes.QuickSettings)
 
     /**
      * Returns a flow that uses scene transition progress to and from a scene that is pulled down
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt
index 21a782e..1f78ae8 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt
@@ -19,7 +19,7 @@
 import com.android.keyguard.LockIconViewController
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.ShadeLockscreenInteractor
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -87,7 +87,7 @@
 
     private fun changeToShadeScene() {
         sceneInteractor.changeScene(
-            SceneKey.Shade,
+            Scenes.Shade,
             "ShadeLockscreenInteractorImpl.expandToNotifications",
         )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt
index 9715070..84afbed 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt
@@ -19,8 +19,11 @@
 import android.content.Context
 import android.content.res.Configuration
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.qs.QS
+import com.android.systemui.scene.domain.interactor.PanelExpansionInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.shade.PanelState
 import com.android.systemui.shade.ShadeExpansionChangeEvent
 import com.android.systemui.shade.ShadeExpansionStateManager
@@ -31,21 +34,26 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.SplitShadeStateController
+import dagger.Lazy
 import java.io.PrintWriter
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
 
 /** Controls the shade expansion transition on non-lockscreen. */
 @SysUISingleton
 class ShadeTransitionController
 @Inject
 constructor(
+    @Application private val applicationScope: CoroutineScope,
     configurationController: ConfigurationController,
     shadeExpansionStateManager: ShadeExpansionStateManager,
     dumpManager: DumpManager,
     private val context: Context,
     private val scrimShadeTransitionController: ScrimShadeTransitionController,
     private val statusBarStateController: SysuiStatusBarStateController,
-    private val splitShadeStateController: SplitShadeStateController
+    private val splitShadeStateController: SplitShadeStateController,
+    private val panelExpansionInteractor: Lazy<PanelExpansionInteractor>,
 ) {
 
     lateinit var shadeViewController: ShadeViewController
@@ -63,11 +71,27 @@
                 override fun onConfigChanged(newConfig: Configuration?) {
                     updateResources()
                 }
-            })
-        val currentState =
-            shadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged)
-        onPanelExpansionChanged(currentState)
-        shadeExpansionStateManager.addStateListener(this::onPanelStateChanged)
+            }
+        )
+        if (SceneContainerFlag.isEnabled) {
+            applicationScope.launch {
+                panelExpansionInteractor.get().legacyPanelExpansion.collect { panelExpansion ->
+                    onPanelExpansionChanged(
+                        ShadeExpansionChangeEvent(
+                            fraction = panelExpansion,
+                            expanded = panelExpansion > 0f,
+                            tracking = true,
+                            dragDownPxAmount = 0f,
+                        )
+                    )
+                }
+            }
+        } else {
+            val currentState =
+                shadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged)
+            onPanelExpansionChanged(currentState)
+            shadeExpansionStateManager.addStateListener(this::onPanelStateChanged)
+        }
         dumpManager.registerCriticalDumpable("ShadeTransitionController") { printWriter, _ ->
             dump(printWriter)
         }
@@ -98,7 +122,9 @@
                 qs.isInitialized: ${this::qs.isInitialized}
                 npvc.isInitialized: ${this::shadeViewController.isInitialized}
                 nssl.isInitialized: ${this::notificationStackScrollLayoutController.isInitialized}
-            """.trimIndent())
+            """
+                .trimIndent()
+        )
     }
 
     private fun isScreenUnlocked() =
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 38358a8..c9aa51c 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
@@ -16,12 +16,13 @@
 
 package com.android.systemui.shade.ui.viewmodel
 
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
 import com.android.systemui.media.controls.domain.pipeline.MediaDataManager
 import com.android.systemui.qs.ui.adapter.QSSceneAdapter
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -67,7 +68,7 @@
     /** Whether or not the shade container should be clickable. */
     val isClickable: StateFlow<Boolean> =
         upDestinationSceneKey
-            .map { it == SceneKey.Lockscreen }
+            .map { it == Scenes.Lockscreen }
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.WhileSubscribed(),
@@ -82,9 +83,9 @@
         canSwipeToDismiss: Boolean?,
     ): SceneKey {
         return when {
-            canSwipeToDismiss == true -> SceneKey.Lockscreen
-            isUnlocked -> SceneKey.Gone
-            else -> SceneKey.Lockscreen
+            canSwipeToDismiss == true -> Scenes.Lockscreen
+            isUnlocked -> Scenes.Gone
+            else -> Scenes.Lockscreen
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BatteryStatusChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BatteryStatusChip.kt
index 8352250..a58ce41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BatteryStatusChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BatteryStatusChip.kt
@@ -22,7 +22,9 @@
 import android.view.View
 import android.widget.FrameLayout
 import android.widget.LinearLayout
+import com.android.settingslib.flags.Flags.newStatusBarIcons
 import com.android.systemui.battery.BatteryMeterView
+import com.android.systemui.battery.unified.BatteryColors
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.events.BackgroundAnimatableView
 
@@ -39,8 +41,12 @@
         roundedContainer = requireViewById(R.id.rounded_container)
         batteryMeterView = requireViewById(R.id.battery_meter_view)
         batteryMeterView.setStaticColor(true)
-        val primaryColor = context.resources.getColor(android.R.color.black, context.theme)
-        batteryMeterView.updateColors(primaryColor, primaryColor, primaryColor)
+        if (newStatusBarIcons()) {
+            batteryMeterView.setUnifiedBatteryColors(BatteryColors.LightThemeColors)
+        } else {
+            val primaryColor = context.resources.getColor(android.R.color.black, context.theme)
+            batteryMeterView.updateColors(primaryColor, primaryColor, primaryColor)
+        }
         updateResources()
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 3908ede..bb81683 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -168,7 +168,7 @@
     private static final int MSG_UNREGISTER_NEARBY_MEDIA_DEVICE_PROVIDER = 67 << MSG_SHIFT;
     private static final int MSG_TILE_SERVICE_REQUEST_LISTENING_STATE = 68 << MSG_SHIFT;
     private static final int MSG_SHOW_REAR_DISPLAY_DIALOG = 69 << MSG_SHIFT;
-    private static final int MSG_GO_TO_FULLSCREEN_FROM_SPLIT = 70 << MSG_SHIFT;
+    private static final int MSG_MOVE_FOCUSED_TASK_TO_FULLSCREEN = 70 << MSG_SHIFT;
     private static final int MSG_ENTER_STAGE_SPLIT_FROM_RUNNING_APP = 71 << MSG_SHIFT;
     private static final int MSG_SHOW_MEDIA_OUTPUT_SWITCHER = 72 << MSG_SHIFT;
     private static final int MSG_TOGGLE_TASKBAR = 73 << MSG_SHIFT;
@@ -498,9 +498,9 @@
         default void showRearDisplayDialog(int currentBaseState) {}
 
         /**
-         * @see IStatusBar#goToFullscreenFromSplit
+         * @see IStatusBar#moveFocusedTaskToFullscreen
          */
-        default void goToFullscreenFromSplit() {}
+        default void moveFocusedTaskToFullscreen(int displayId) {}
 
         /**
          * @see IStatusBar#enterStageSplitFromRunningApp
@@ -615,7 +615,14 @@
             args.argi2 = state1;
             args.argi3 = state2;
             args.argi4 = animate ? 1 : 0;
-            mHandler.obtainMessage(MSG_DISABLE, args).sendToTarget();
+            Message msg = mHandler.obtainMessage(MSG_DISABLE, args);
+            if (Looper.myLooper() == mHandler.getLooper()) {
+                // If its the right looper execute immediately so hides can be handled quickly.
+                mHandler.handleMessage(msg);
+                msg.recycle();
+            } else {
+                msg.sendToTarget();
+            }
         }
     }
 
@@ -1415,8 +1422,10 @@
     }
 
     @Override
-    public void goToFullscreenFromSplit() {
-        mHandler.obtainMessage(MSG_GO_TO_FULLSCREEN_FROM_SPLIT).sendToTarget();
+    public void moveFocusedTaskToFullscreen(int displayId) {
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = displayId;
+        mHandler.obtainMessage(MSG_MOVE_FOCUSED_TASK_TO_FULLSCREEN, args).sendToTarget();
     }
 
     @Override
@@ -1890,11 +1899,14 @@
                         mCallbacks.get(i).showRearDisplayDialog((Integer) msg.obj);
                     }
                     break;
-                case MSG_GO_TO_FULLSCREEN_FROM_SPLIT:
+                case MSG_MOVE_FOCUSED_TASK_TO_FULLSCREEN: {
+                    args = (SomeArgs) msg.obj;
+                    int displayId = args.argi1;
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).goToFullscreenFromSplit();
+                        mCallbacks.get(i).moveFocusedTaskToFullscreen(displayId);
                     }
                     break;
+                }
                 case MSG_ENTER_STAGE_SPLIT_FROM_RUNNING_APP:
                     for (int i = 0; i < mCallbacks.size(); i++) {
                         mCallbacks.get(i).enterStageSplitFromRunningApp((Boolean) msg.obj);
@@ -1920,13 +1932,14 @@
                         mCallbacks.get(i).immersiveModeChanged(rootDisplayAreaId, isImmersiveMode);
                     }
                     break;
-                case MSG_ENTER_DESKTOP:
+                case MSG_ENTER_DESKTOP: {
                     args = (SomeArgs) msg.obj;
                     int displayId = args.argi1;
                     for (int i = 0; i < mCallbacks.size(); i++) {
                         mCallbacks.get(i).enterDesktop(displayId);
                     }
                     break;
+                }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
index a4741a5..ef4e530 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
@@ -482,11 +482,30 @@
                         context.getString(R.string.keyboard_shortcut_group_system),
                         new ArrayList<>());
         List<ShortcutKeyGroupMultiMappingInfo> infoList = Arrays.asList(
-                /* Access notification shade: Meta + N */
+                /* Access list of all apps and search (i.e. Search/Launcher): Meta */
                 new ShortcutKeyGroupMultiMappingInfo(
-                        context.getString(R.string.group_system_access_notification_shade),
+                        context.getString(R.string.group_system_access_all_apps_search),
                         Arrays.asList(
-                                Pair.create(KeyEvent.KEYCODE_N, KeyEvent.META_META_ON))),
+                                Pair.create(KeyEvent.KEYCODE_UNKNOWN, KeyEvent.META_META_ON))),
+                /* Access home screen: Meta + H, Meta + Enter */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_access_home_screen),
+                        Arrays.asList(
+                                Pair.create(KeyEvent.KEYCODE_H, KeyEvent.META_META_ON),
+                                Pair.create(KeyEvent.KEYCODE_ENTER, KeyEvent.META_META_ON))),
+                /* Overview of open apps: Meta + Tab */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_overview_open_apps),
+                        Arrays.asList(
+                                Pair.create(KeyEvent.KEYCODE_TAB, KeyEvent.META_META_ON))),
+                /* Back: go back to previous state (back button) */
+                /* Meta + Escape, Meta + backspace, Meta + left arrow */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_go_back),
+                        Arrays.asList(
+                                Pair.create(KeyEvent.KEYCODE_ESCAPE, KeyEvent.META_META_ON),
+                                Pair.create(KeyEvent.KEYCODE_DEL, KeyEvent.META_META_ON),
+                                Pair.create(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.META_META_ON))),
                 /* Take a full screenshot: Meta + Ctrl + S */
                 new ShortcutKeyGroupMultiMappingInfo(
                         context.getString(R.string.group_system_full_screenshot),
@@ -499,25 +518,6 @@
                         context.getString(R.string.group_system_access_system_app_shortcuts),
                         Arrays.asList(
                                 Pair.create(KeyEvent.KEYCODE_SLASH, KeyEvent.META_META_ON))),
-                /* Back: go back to previous state (back button) */
-                /* Meta + Escape, Meta + Grave, Meta + backspace, Meta + left arrow */
-                new ShortcutKeyGroupMultiMappingInfo(
-                        context.getString(R.string.group_system_go_back),
-                        Arrays.asList(
-                                Pair.create(KeyEvent.KEYCODE_ESCAPE, KeyEvent.META_META_ON),
-                                Pair.create(KeyEvent.KEYCODE_DEL, KeyEvent.META_META_ON),
-                                Pair.create(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.META_META_ON))),
-                /* Access home screen: Meta + H, Meta + Enter */
-                new ShortcutKeyGroupMultiMappingInfo(
-                        context.getString(R.string.group_system_access_home_screen),
-                        Arrays.asList(
-                                Pair.create(KeyEvent.KEYCODE_H, KeyEvent.META_META_ON),
-                                Pair.create(KeyEvent.KEYCODE_ENTER, KeyEvent.META_META_ON))),
-                /* Overview of open apps: Meta + Tab */
-                new ShortcutKeyGroupMultiMappingInfo(
-                        context.getString(R.string.group_system_overview_open_apps),
-                        Arrays.asList(
-                                Pair.create(KeyEvent.KEYCODE_TAB, KeyEvent.META_META_ON))),
                 /* Cycle through recent apps (forward): Alt + Tab */
                 new ShortcutKeyGroupMultiMappingInfo(
                         context.getString(R.string.group_system_cycle_forward),
@@ -530,26 +530,16 @@
                                 Pair.create(
                                         KeyEvent.KEYCODE_TAB,
                                         KeyEvent.META_SHIFT_ON | KeyEvent.META_ALT_ON))),
-                /* Access list of all apps and search (i.e. Search/Launcher): Meta */
-                new ShortcutKeyGroupMultiMappingInfo(
-                        context.getString(R.string.group_system_access_all_apps_search),
-                        Arrays.asList(
-                                Pair.create(KeyEvent.KEYCODE_UNKNOWN, KeyEvent.META_META_ON))),
                 /* Hide and (re)show taskbar: Meta + T */
                 new ShortcutKeyGroupMultiMappingInfo(
                         context.getString(R.string.group_system_hide_reshow_taskbar),
                         Arrays.asList(
                                 Pair.create(KeyEvent.KEYCODE_T, KeyEvent.META_META_ON))),
-                /* Access system settings: Meta + I */
+                /* Access notification shade: Meta + N */
                 new ShortcutKeyGroupMultiMappingInfo(
-                        context.getString(R.string.group_system_access_system_settings),
+                        context.getString(R.string.group_system_access_notification_shade),
                         Arrays.asList(
-                                Pair.create(KeyEvent.KEYCODE_I, KeyEvent.META_META_ON))),
-                /* Access Google Assistant: Meta + A */
-                new ShortcutKeyGroupMultiMappingInfo(
-                        context.getString(R.string.group_system_access_google_assistant),
-                        Arrays.asList(
-                                Pair.create(KeyEvent.KEYCODE_A, KeyEvent.META_META_ON))),
+                                Pair.create(KeyEvent.KEYCODE_N, KeyEvent.META_META_ON))),
                 /*  Lock screen: Meta + L */
                 new ShortcutKeyGroupMultiMappingInfo(
                         context.getString(R.string.group_system_lock_screen),
@@ -561,7 +551,17 @@
                         Arrays.asList(
                                 Pair.create(
                                         KeyEvent.KEYCODE_N,
-                                        KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON)))
+                                        KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON))),
+                /* Access system settings: Meta + I */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_access_system_settings),
+                        Arrays.asList(
+                                Pair.create(KeyEvent.KEYCODE_I, KeyEvent.META_META_ON))),
+                /* Access Google Assistant: Meta + A */
+                new ShortcutKeyGroupMultiMappingInfo(
+                        context.getString(R.string.group_system_access_google_assistant),
+                        Arrays.asList(
+                                Pair.create(KeyEvent.KEYCODE_A, KeyEvent.META_META_ON)))
         );
         for (ShortcutKeyGroupMultiMappingInfo info : infoList) {
             systemGroup.addItem(info.getShortcutMultiMappingInfo());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 19fe60a..1ec86ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -71,6 +71,7 @@
 import android.provider.DeviceConfig;
 import android.text.TextUtils;
 import android.text.format.Formatter;
+import android.util.Pair;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityManager;
@@ -187,6 +188,7 @@
     private CharSequence mTransientIndication;
     private CharSequence mBiometricMessage;
     private CharSequence mBiometricMessageFollowUp;
+    private BiometricSourceType mBiometricMessageSource;
     protected ColorStateList mInitialTextColorState;
     private boolean mVisible;
     private boolean mOrganizationOwnedDevice;
@@ -206,7 +208,7 @@
     private int mBatteryLevel;
     private boolean mBatteryPresent = true;
     private long mChargingTimeRemaining;
-    private String mBiometricErrorMessageToShowOnScreenOn;
+    private Pair<String, BiometricSourceType> mBiometricErrorMessageToShowOnScreenOn;
     private final Set<Integer> mCoExFaceAcquisitionMsgIdsToShow;
     private final FaceHelpMessageDeferral mFaceAcquiredMessageDeferral;
     private boolean mInited;
@@ -225,15 +227,18 @@
                 mIsActiveDreamLockscreenHosted = isLockscreenHosted;
                 updateDeviceEntryIndication(false);
             };
-    private final ScreenLifecycle.Observer mScreenObserver =
-            new ScreenLifecycle.Observer() {
+    private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
         @Override
         public void onScreenTurnedOn() {
             mHandler.removeMessages(MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON);
             if (mBiometricErrorMessageToShowOnScreenOn != null) {
                 String followUpMessage = mFaceLockedOutThisAuthSession
                         ? faceLockedOutFollowupMessage() : null;
-                showBiometricMessage(mBiometricErrorMessageToShowOnScreenOn, followUpMessage);
+                showBiometricMessage(
+                        mBiometricErrorMessageToShowOnScreenOn.first,
+                        followUpMessage,
+                        mBiometricErrorMessageToShowOnScreenOn.second
+                );
                 // We want to keep this message around in case the screen was off
                 hideBiometricMessageDelayed(DEFAULT_HIDE_DELAY_MS);
                 mBiometricErrorMessageToShowOnScreenOn = null;
@@ -879,8 +884,35 @@
         updateTransient();
     }
 
-    private void showBiometricMessage(CharSequence biometricMessage) {
-        showBiometricMessage(biometricMessage, null);
+    private void showSuccessBiometricMessage(
+            CharSequence biometricMessage,
+            @Nullable CharSequence biometricMessageFollowUp,
+            BiometricSourceType biometricSourceType
+    ) {
+        showBiometricMessage(biometricMessage, biometricMessageFollowUp, biometricSourceType, true);
+    }
+
+    private void showSuccessBiometricMessage(CharSequence biometricMessage,
+            BiometricSourceType biometricSourceType) {
+        showSuccessBiometricMessage(biometricMessage, null, biometricSourceType);
+    }
+
+    private void showBiometricMessage(CharSequence biometricMessage,
+            BiometricSourceType biometricSourceType) {
+        showBiometricMessage(biometricMessage, null, biometricSourceType, false);
+    }
+
+    private void showBiometricMessage(
+            CharSequence biometricMessage,
+            @Nullable CharSequence biometricMessageFollowUp,
+            BiometricSourceType biometricSourceType
+    ) {
+        showBiometricMessage(
+                biometricMessage,
+                biometricMessageFollowUp,
+                biometricSourceType,
+                false
+        );
     }
 
     /**
@@ -889,15 +921,33 @@
      * by {@link KeyguardIndicationRotateTextViewController}, see class for rotating message
      * logic.
      */
-    private void showBiometricMessage(CharSequence biometricMessage,
-            @Nullable CharSequence biometricMessageFollowUp) {
+    private void showBiometricMessage(
+            CharSequence biometricMessage,
+            @Nullable CharSequence biometricMessageFollowUp,
+            BiometricSourceType biometricSourceType,
+            boolean isSuccessMessage
+    ) {
         if (TextUtils.equals(biometricMessage, mBiometricMessage)
+                && biometricSourceType == mBiometricMessageSource
                 && TextUtils.equals(biometricMessageFollowUp, mBiometricMessageFollowUp)) {
             return;
         }
 
+        if (!isSuccessMessage
+                && mBiometricMessageSource == FINGERPRINT
+                && biometricSourceType != FINGERPRINT) {
+            // drop all non-fingerprint biometric messages if there's a fingerprint message showing
+            mKeyguardLogger.logDropNonFingerprintMessage(
+                    biometricMessage,
+                    biometricMessageFollowUp,
+                    biometricSourceType
+            );
+            return;
+        }
+
         mBiometricMessage = biometricMessage;
         mBiometricMessageFollowUp = biometricMessageFollowUp;
+        mBiometricMessageSource = biometricSourceType;
 
         mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK);
         hideBiometricMessageDelayed(
@@ -914,6 +964,7 @@
         if (mBiometricMessage != null || mBiometricMessageFollowUp != null) {
             mBiometricMessage = null;
             mBiometricMessageFollowUp = null;
+            mBiometricMessageSource = null;
             mHideBiometricMessageHandler.cancel();
             updateBiometricMessage();
         }
@@ -1085,7 +1136,8 @@
                 } else {
                     message = mContext.getString(R.string.keyguard_retry);
                 }
-                mStatusBarKeyguardViewManager.setKeyguardMessage(message, mInitialTextColorState);
+                mStatusBarKeyguardViewManager.setKeyguardMessage(message, mInitialTextColorState,
+                        null);
             }
         } else {
             final boolean canSkipBouncer = mKeyguardUpdateMonitor.getUserCanSkipBouncer(
@@ -1097,34 +1149,40 @@
                         || mAccessibilityManager.isTouchExplorationEnabled();
                 if (udfpsSupported && faceAuthenticated) { // co-ex
                     if (a11yEnabled) {
-                        showBiometricMessage(
+                        showSuccessBiometricMessage(
                                 mContext.getString(R.string.keyguard_face_successful_unlock),
-                                mContext.getString(R.string.keyguard_unlock)
+                                mContext.getString(R.string.keyguard_unlock),
+                                FACE
                         );
                     } else {
-                        showBiometricMessage(
+                        showSuccessBiometricMessage(
                                 mContext.getString(R.string.keyguard_face_successful_unlock),
-                                mContext.getString(R.string.keyguard_unlock_press)
+                                mContext.getString(R.string.keyguard_unlock_press),
+                                FACE
                         );
                     }
                 } else if (faceAuthenticated) { // face-only
-                    showBiometricMessage(
+                    showSuccessBiometricMessage(
                             mContext.getString(R.string.keyguard_face_successful_unlock),
-                            mContext.getString(R.string.keyguard_unlock)
+                            mContext.getString(R.string.keyguard_unlock),
+                            FACE
                     );
                 } else if (udfpsSupported) { // udfps-only
                     if (a11yEnabled) {
-                        showBiometricMessage(mContext.getString(R.string.keyguard_unlock));
+                        showSuccessBiometricMessage(
+                                mContext.getString(R.string.keyguard_unlock),
+                                null
+                        );
                     } else {
-                        showBiometricMessage(mContext.getString(
-                                R.string.keyguard_unlock_press));
+                        showSuccessBiometricMessage(mContext.getString(
+                                R.string.keyguard_unlock_press), null);
                     }
                 } else { // no security or unlocked by a trust agent
-                    showBiometricMessage(mContext.getString(R.string.keyguard_unlock));
+                    showSuccessBiometricMessage(mContext.getString(R.string.keyguard_unlock), null);
                 }
             } else {
                 // suggest swiping up for the primary authentication bouncer
-                showBiometricMessage(mContext.getString(R.string.keyguard_unlock));
+                showBiometricMessage(mContext.getString(R.string.keyguard_unlock), null);
             }
         }
     }
@@ -1228,6 +1286,13 @@
                     && msgId != BIOMETRIC_HELP_FACE_NOT_AVAILABLE;
             final boolean faceAuthFailed = biometricSourceType == FACE
                     && msgId == BIOMETRIC_HELP_FACE_NOT_RECOGNIZED; // ran through matcher & failed
+            if (faceAuthFailed && mFaceLockedOutThisAuthSession) {
+                mKeyguardLogger.logBiometricMessage(
+                        "skipped showing faceAuthFailed message due to lockout",
+                        msgId,
+                        helpString);
+                return;
+            }
             final boolean fpAuthFailed = biometricSourceType == FINGERPRINT
                     && msgId == BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED; // ran matcher & failed
             final boolean isUnlockWithFingerprintPossible = canUnlockWithFingerprint();
@@ -1245,49 +1310,55 @@
                     mBouncerMessageInteractor.setFaceAcquisitionMessage(helpString);
                 }
                 mStatusBarKeyguardViewManager.setKeyguardMessage(helpString,
-                        mInitialTextColorState);
+                        mInitialTextColorState, biometricSourceType);
             } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
                 if (isCoExFaceAcquisitionMessage && msgId == FACE_ACQUIRED_TOO_DARK) {
                     showBiometricMessage(
                             helpString,
-                            mContext.getString(R.string.keyguard_suggest_fingerprint)
+                            mContext.getString(R.string.keyguard_suggest_fingerprint),
+                            biometricSourceType
                     );
                 } else if (faceAuthFailed && isUnlockWithFingerprintPossible) {
                     showBiometricMessage(
                             mContext.getString(R.string.keyguard_face_failed),
-                            mContext.getString(R.string.keyguard_suggest_fingerprint)
+                            mContext.getString(R.string.keyguard_suggest_fingerprint),
+                            biometricSourceType
                     );
                 } else if (fpAuthFailed
                         && mKeyguardUpdateMonitor.isCurrentUserUnlockedWithFace()) {
                     // face had already previously unlocked the device, so instead of showing a
                     // fingerprint error, tell them they have already unlocked with face auth
                     // and how to enter their device
-                    showBiometricMessage(
+                    showSuccessBiometricMessage(
                             mContext.getString(R.string.keyguard_face_successful_unlock),
-                            mContext.getString(R.string.keyguard_unlock)
+                            mContext.getString(R.string.keyguard_unlock),
+                            null
                     );
                 } else if (fpAuthFailed
                         && mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser())) {
-                    showBiometricMessage(
+                    showSuccessBiometricMessage(
                             getTrustGrantedIndication(),
-                            mContext.getString(R.string.keyguard_unlock)
+                            mContext.getString(R.string.keyguard_unlock),
+                            null
                     );
                 } else if (faceAuthUnavailable) {
                     showBiometricMessage(
                             helpString,
                             isUnlockWithFingerprintPossible
                                     ? mContext.getString(R.string.keyguard_suggest_fingerprint)
-                                    : mContext.getString(R.string.keyguard_unlock)
+                                    : mContext.getString(R.string.keyguard_unlock),
+                            biometricSourceType
                     );
                 } else {
-                    showBiometricMessage(helpString);
+                    showBiometricMessage(helpString, biometricSourceType);
                 }
             } else if (faceAuthFailed) {
                 // show action to unlock
                 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_ACTION_TO_UNLOCK),
                         TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
             } else {
-                mBiometricErrorMessageToShowOnScreenOn = helpString;
+                mBiometricErrorMessageToShowOnScreenOn =
+                        new Pair<>(helpString, biometricSourceType);
                 mHandler.sendMessageDelayed(
                         mHandler.obtainMessage(MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON),
                         1000);
@@ -1333,7 +1404,7 @@
             } else if (mIndicationHelper.isFaceLockoutErrorMsg(msgId)) {
                 handleFaceLockoutError(errString);
             } else {
-                showErrorMessageNowOrLater(errString, null);
+                showErrorMessageNowOrLater(errString, null, FACE);
             }
         }
 
@@ -1343,7 +1414,7 @@
                         msgId,
                         errString);
             } else {
-                showErrorMessageNowOrLater(errString, null);
+                showErrorMessageNowOrLater(errString, null, FINGERPRINT);
             }
         }
 
@@ -1371,7 +1442,7 @@
 
         @Override
         public void onTrustAgentErrorMessage(CharSequence message) {
-            showBiometricMessage(message);
+            showBiometricMessage(message, null);
         }
 
         @Override
@@ -1459,12 +1530,13 @@
         // had too many unsuccessful attempts.
         if (!mFaceLockedOutThisAuthSession) {
             mFaceLockedOutThisAuthSession = true;
-            showErrorMessageNowOrLater(errString, followupMessage);
+            showErrorMessageNowOrLater(errString, followupMessage, FACE);
         } else if (!mAuthController.isUdfpsFingerDown()) {
             // On subsequent lockouts, we show a more generic locked out message.
             showErrorMessageNowOrLater(
                     mContext.getString(R.string.keyguard_face_unlock_unavailable),
-                    followupMessage);
+                    followupMessage,
+                    FACE);
         }
     }
 
@@ -1484,7 +1556,8 @@
                     && !mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 showBiometricMessage(
                         deferredFaceMessage,
-                        mContext.getString(R.string.keyguard_suggest_fingerprint)
+                        mContext.getString(R.string.keyguard_suggest_fingerprint),
+                        FACE
                 );
             } else {
                 // otherwise, don't show any message
@@ -1496,7 +1569,8 @@
             // user to manually retry.
             showBiometricMessage(
                     deferredFaceMessage,
-                    mContext.getString(R.string.keyguard_unlock)
+                    mContext.getString(R.string.keyguard_unlock),
+                    FACE
             );
         } else {
             // Face-only
@@ -1510,13 +1584,15 @@
                 getCurrentUser()) && mKeyguardUpdateMonitor.isUnlockingWithFingerprintAllowed();
     }
 
-    private void showErrorMessageNowOrLater(String errString, @Nullable String followUpMsg) {
+    private void showErrorMessageNowOrLater(String errString, @Nullable String followUpMsg,
+            BiometricSourceType biometricSourceType) {
         if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
-            mStatusBarKeyguardViewManager.setKeyguardMessage(errString, mInitialTextColorState);
+            mStatusBarKeyguardViewManager.setKeyguardMessage(errString, mInitialTextColorState,
+                    biometricSourceType);
         } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
-            showBiometricMessage(errString, followUpMsg);
+            showBiometricMessage(errString, followUpMsg, biometricSourceType);
         } else {
-            mBiometricErrorMessageToShowOnScreenOn = errString;
+            mBiometricErrorMessageToShowOnScreenOn = new Pair<>(errString, biometricSourceType);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java
index 143fc32..3cf61e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java
@@ -34,6 +34,8 @@
 import com.android.internal.widget.ImageFloatingTextView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationContentView;
+import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
+import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -253,7 +255,8 @@
         }
 
         public void init() {
-            View header = mParentRow.getNotificationViewWrapper().getNotificationHeader();
+            NotificationViewWrapper wrapper = mParentRow.getNotificationViewWrapper();
+            View header = wrapper == null ? null : wrapper.getNotificationHeader();
             mParentView = header == null ? null : header.findViewById(mId);
             mParentData = mExtractor == null ? null : mExtractor.extractData(mParentRow);
             mApply = !mComparator.isEmpty(mParentView);
@@ -326,6 +329,9 @@
 
         @Override
         public boolean isEmpty(View view) {
+            if (AsyncGroupHeaderViewInflation.isEnabled() && view == null) {
+                return true;
+            }
             if (view instanceof ImageView) {
                 return ((ImageView) view).getDrawable() == null;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 36fc9bb..e0dd7f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -36,6 +36,7 @@
 import androidx.annotation.NonNull;
 
 import com.android.app.animation.Interpolators;
+import com.android.compose.animation.scene.SceneKey;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.jank.InteractionJankMonitor;
@@ -49,7 +50,7 @@
 import com.android.systemui.res.R;
 import com.android.systemui.scene.domain.interactor.SceneInteractor;
 import com.android.systemui.scene.shared.flag.SceneContainerFlag;
-import com.android.systemui.scene.shared.model.SceneKey;
+import com.android.systemui.scene.shared.model.Scenes;
 import com.android.systemui.shade.domain.interactor.ShadeInteractor;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.policy.CallbackController;
@@ -659,11 +660,11 @@
     }
 
     private static final Map<SceneKey, Integer> sStatusBarStateByLockedSceneKey = Map.of(
-            SceneKey.Lockscreen.INSTANCE, StatusBarState.KEYGUARD,
-            SceneKey.Bouncer.INSTANCE, StatusBarState.KEYGUARD,
-            SceneKey.Communal.INSTANCE, StatusBarState.KEYGUARD,
-            SceneKey.Shade.INSTANCE, StatusBarState.SHADE_LOCKED,
-            SceneKey.QuickSettings.INSTANCE, StatusBarState.SHADE_LOCKED
+            Scenes.Lockscreen, StatusBarState.KEYGUARD,
+            Scenes.Bouncer, StatusBarState.KEYGUARD,
+            Scenes.Communal, StatusBarState.KEYGUARD,
+            Scenes.Shade, StatusBarState.SHADE_LOCKED,
+            Scenes.QuickSettings, StatusBarState.SHADE_LOCKED
     );
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiIcons.java
index e582a01..dbcda41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiIcons.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.connectivity;
 
+import static com.android.settingslib.flags.Flags.newStatusBarIcons;
+
 import com.android.settingslib.AccessibilityContentDescriptions;
 import com.android.settingslib.R;
 import com.android.settingslib.SignalIcon.IconGroup;
@@ -23,21 +25,52 @@
 /** */
 public class WifiIcons {
 
-    public static final int[] WIFI_FULL_ICONS = {
-            com.android.internal.R.drawable.ic_wifi_signal_0,
-            com.android.internal.R.drawable.ic_wifi_signal_1,
-            com.android.internal.R.drawable.ic_wifi_signal_2,
-            com.android.internal.R.drawable.ic_wifi_signal_3,
-            com.android.internal.R.drawable.ic_wifi_signal_4
-    };
+    public static final int[] WIFI_FULL_ICONS = getIconsBasedOnFlag();
 
-    public static final int[] WIFI_NO_INTERNET_ICONS = {
-            R.drawable.ic_no_internet_wifi_signal_0,
-            R.drawable.ic_no_internet_wifi_signal_1,
-            R.drawable.ic_no_internet_wifi_signal_2,
-            R.drawable.ic_no_internet_wifi_signal_3,
-            R.drawable.ic_no_internet_wifi_signal_4
-    };
+    /**
+     * Check the aconfig flag to decide on which icons to use. Can be removed once the flag is gone
+     */
+    private static int[] getIconsBasedOnFlag() {
+        if (newStatusBarIcons()) {
+            return new int[] {
+                R.drawable.ic_wifi_0,
+                R.drawable.ic_wifi_1,
+                R.drawable.ic_wifi_2,
+                R.drawable.ic_wifi_3,
+                R.drawable.ic_wifi_4
+            };
+        } else {
+            return new int[] {
+                com.android.internal.R.drawable.ic_wifi_signal_0,
+                com.android.internal.R.drawable.ic_wifi_signal_1,
+                com.android.internal.R.drawable.ic_wifi_signal_2,
+                com.android.internal.R.drawable.ic_wifi_signal_3,
+                com.android.internal.R.drawable.ic_wifi_signal_4
+            };
+        }
+    }
+
+    public static final int[] WIFI_NO_INTERNET_ICONS = getErrorIconsBasedOnFlag();
+
+    private static int [] getErrorIconsBasedOnFlag() {
+        if (newStatusBarIcons()) {
+            return new int[] {
+                R.drawable.ic_wifi_0_error,
+                R.drawable.ic_wifi_1_error,
+                R.drawable.ic_wifi_2_error,
+                R.drawable.ic_wifi_3_error,
+                R.drawable.ic_wifi_4_error
+            };
+        } else {
+            return new int[] {
+                R.drawable.ic_no_internet_wifi_signal_0,
+                R.drawable.ic_no_internet_wifi_signal_1,
+                R.drawable.ic_no_internet_wifi_signal_2,
+                R.drawable.ic_no_internet_wifi_signal_3,
+                R.drawable.ic_no_internet_wifi_signal_4
+            };
+        }
+    }
 
     public static final int[][] QS_WIFI_SIGNAL_STRENGTH = {
             WIFI_NO_INTERNET_ICONS,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 599600d6..0fd0555 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -39,7 +39,6 @@
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.settingslib.Utils
 import com.android.systemui.Dumpable
-import com.android.systemui.res.R
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
@@ -54,6 +53,7 @@
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.plugins.clocks.WeatherData
 import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.shared.regionsampling.RegionSampler
 import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DATE_SMARTSPACE_DATA_PLUGIN
@@ -68,11 +68,14 @@
 import com.android.systemui.util.time.SystemClock
 import java.io.PrintWriter
 import java.time.Instant
+import java.util.Deque
+import java.util.LinkedList
 import java.util.Optional
 import java.util.concurrent.Executor
 import javax.inject.Inject
 import javax.inject.Named
 
+
 /** Controller for managing the smartspace view on the lockscreen */
 @SysUISingleton
 class LockscreenSmartspaceController
@@ -106,6 +109,8 @@
 ) : Dumpable {
     companion object {
         private const val TAG = "LockscreenSmartspaceController"
+
+        private const val MAX_RECENT_SMARTSPACE_DATA_FOR_DUMP = 5
     }
 
     private var session: SmartspaceSession? = null
@@ -114,6 +119,9 @@
     private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
     private val configPlugin: BcSmartspaceConfigPlugin? = optionalConfigPlugin.orElse(null)
 
+    // This stores recently received Smartspace pushes to be included in dumpsys.
+    private val recentSmartspaceData: Deque<List<SmartspaceTarget>> = LinkedList()
+
     // Smartspace can be used on multiple displays, such as when the user casts their screen
     private var smartspaceViews = mutableSetOf<SmartspaceView>()
     private var regionSamplers =
@@ -173,6 +181,7 @@
 
         // The weather data plugin takes unfiltered targets and performs the filtering internally.
         weatherPlugin?.onTargetsAvailable(targets)
+
         val now = Instant.ofEpochMilli(systemClock.currentTimeMillis())
         val weatherTarget = targets.find { t ->
             t.featureType == SmartspaceTarget.FEATURE_WEATHER &&
@@ -201,6 +210,14 @@
         }
 
         val filteredTargets = targets.filter(::filterSmartspaceTarget)
+
+        synchronized(recentSmartspaceData) {
+            recentSmartspaceData.offerLast(filteredTargets)
+            if (recentSmartspaceData.size > MAX_RECENT_SMARTSPACE_DATA_FOR_DUMP) {
+                recentSmartspaceData.pollFirst()
+            }
+        }
+
         plugin?.onTargetsAvailable(filteredTargets)
     }
 
@@ -588,9 +605,26 @@
         return null
     }
 
-    override fun dump(pw: PrintWriter, args: Array<out String>) = pw.asIndenting().run {
-        printCollection("Region Samplers", regionSamplers.values) {
-            it.dump(this)
+    override fun dump(pw: PrintWriter, args: Array<out String>) {
+        pw.asIndenting().run {
+            printCollection("Region Samplers", regionSamplers.values) {
+                it.dump(this)
+            }
+        }
+
+        pw.println("Recent BC Smartspace Targets (most recent first)")
+        synchronized(recentSmartspaceData) {
+            if (recentSmartspaceData.size === 0) {
+                pw.println("   No data\n")
+                return
+            }
+            recentSmartspaceData.descendingIterator().forEachRemaining { smartspaceTargets ->
+                pw.println("   Number of targets: ${smartspaceTargets.size}")
+                for (target in smartspaceTargets) {
+                    pw.println("      $target")
+                }
+                pw.println()
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
index 639e23a..deaf1d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
@@ -363,10 +363,11 @@
 
     NotifInflater.Params getInflaterParams(NotifUiAdjustment adjustment, String reason) {
         return new NotifInflater.Params(
-                adjustment.isMinimized(),
-                reason,
-                adjustment.isSnoozeEnabled(),
-                adjustment.isChildInGroup()
+                /* isLowPriority = */ adjustment.isMinimized(),
+                /* reason = */ reason,
+                /* showSnooze = */ adjustment.isSnoozeEnabled(),
+                /* isChildInGroup = */ adjustment.isChildInGroup(),
+                /* isGroupSummary = */ adjustment.isGroupSummary()
         );
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinator.kt
index 12de339..4a7b7ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinator.kt
@@ -54,7 +54,7 @@
     }
 
     private fun GroupEntry.calculateLatestAlertTime(): Long {
-        val lastChildAlertedTime = children.maxOf { it.lastAudiblyAlertedMs }
+        val lastChildAlertedTime = children.maxOfOrNull { it.lastAudiblyAlertedMs } ?: 0
         val summaryAlertedTime = checkNotNull(summary).lastAudiblyAlertedMs
         return max(lastChildAlertedTime, summaryAlertedTime)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
index 29627e1..f03c313 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
@@ -119,6 +119,9 @@
             val needsRedaction = lockscreenUserManager.needsRedaction(entry)
             val isSensitive = userPublic && needsRedaction
             entry.setSensitive(isSensitive || shouldProtectNotification, deviceSensitive)
+            if (screenshareNotificationHiding()) {
+                entry.row?.setPublicExpanderVisible(!shouldProtectNotification)
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt
index c0b187b..18460c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt
@@ -60,5 +60,6 @@
         val reason: String,
         val showSnooze: Boolean,
         val isChildInGroup: Boolean = false,
+        val isGroupSummary: Boolean = false,
     )
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt
index e1d2cdc..bab94b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt
@@ -20,6 +20,7 @@
 import android.app.RemoteInput
 import android.graphics.drawable.Icon
 import android.text.TextUtils
+import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation
 import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation
 
 /**
@@ -36,6 +37,7 @@
     val isMinimized: Boolean,
     val needsRedaction: Boolean,
     val isChildInGroup: Boolean,
+    val isGroupSummary: Boolean,
 ) {
     companion object {
         @JvmStatic
@@ -55,6 +57,8 @@
             //  !oldAdjustment.isChildInGroup && newAdjustment.isChildInGroup -> true
             AsyncHybridViewInflation.isEnabled &&
                     oldAdjustment.isChildInGroup != newAdjustment.isChildInGroup -> true
+            AsyncGroupHeaderViewInflation.isEnabled &&
+                !oldAdjustment.isGroupSummary && newAdjustment.isGroupSummary -> true
             else -> false
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt
index 6f44c13..0b9d19d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt
@@ -123,6 +123,7 @@
         isSnoozeEnabled = isSnoozeSettingsEnabled && !entry.isCanceled,
         isMinimized = isEntryMinimized(entry),
         needsRedaction = lockscreenUserManager.needsRedaction(entry),
-        isChildInGroup = groupMembershipManager.isChildInGroup(entry),
+        isChildInGroup = entry.sbn.isAppOrSystemGroupChild,
+        isGroupSummary = entry.sbn.isAppOrSystemGroupSummary,
     )
 }
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 954e805..c5b55c7 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
@@ -21,6 +21,8 @@
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED;
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC;
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_SINGLE_LINE;
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_GROUP_SUMMARY_HEADER;
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER;
 
 import static java.util.Objects.requireNonNull;
 
@@ -50,6 +52,7 @@
 import com.android.systemui.statusbar.notification.row.RowContentBindStage;
 import com.android.systemui.statusbar.notification.row.RowInflaterTask;
 import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
+import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
 import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 
@@ -271,6 +274,17 @@
             }
         }
 
+        if (AsyncGroupHeaderViewInflation.isEnabled()) {
+            if (inflaterParams.isGroupSummary()) {
+                params.requireContentViews(FLAG_GROUP_SUMMARY_HEADER);
+                if (isLowPriority) {
+                    params.requireContentViews(FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER);
+                }
+            } else {
+                params.markContentViewsFreeable(FLAG_GROUP_SUMMARY_HEADER);
+                params.markContentViewsFreeable(FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER);
+            }
+        }
         params.rebindAllContentViews();
         mLogger.logRequestingRebind(entry, inflaterParams);
         mRowContentBindStage.requestRebind(entry, en -> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index 510086d..dc9eeb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -191,11 +191,11 @@
     public boolean shouldBubbleUp(NotificationEntry entry) {
         final StatusBarNotification sbn = entry.getSbn();
 
-        if (!canAlertCommon(entry, true)) {
+        if (!canAlertCommon(entry, false)) {
             return false;
         }
 
-        if (!canAlertAwakeCommon(entry, true)) {
+        if (!canAlertAwakeCommon(entry, false)) {
             return false;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 7358034..61cdea1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -547,13 +547,7 @@
     }
 
     private void setContentAlpha(float contentAlpha) {
-        View contentView = getContentView();
-        if (contentView.hasOverlappingRendering()) {
-            int layerType = contentAlpha == 0.0f || contentAlpha == 1.0f ? LAYER_TYPE_NONE
-                    : LAYER_TYPE_HARDWARE;
-            contentView.setLayerType(layerType, null);
-        }
-        contentView.setAlpha(contentAlpha);
+        setAlphaAndLayerType(getContentView(), contentAlpha);
         // After updating the current view, reset all views.
         if (contentAlpha == 1f) {
             resetAllContentAlphas();
@@ -561,6 +555,19 @@
     }
 
     /**
+     * Set a content view's alpha value and hardware layer type for fluent animations
+     * @param contentView the view to set
+     * @param alpha the alpha value to set
+     */
+    protected void setAlphaAndLayerType(View contentView, float alpha) {
+        if (contentView.hasOverlappingRendering()) {
+            int layerType = alpha == 0.0f || alpha == 1.0f ? LAYER_TYPE_NONE : LAYER_TYPE_HARDWARE;
+            contentView.setLayerType(layerType, null);
+        }
+        contentView.setAlpha(alpha);
+    }
+
+    /**
      * If a subclass's {@link #getContentView()} returns different views depending on state,
      * this method is an opportunity to reset the alpha of ALL content views, not just the
      * current one, which may prevent a content view that is temporarily hidden from being reset.
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 decb244..5f3a83a 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
@@ -100,7 +100,9 @@
 import com.android.systemui.statusbar.notification.logging.NotificationCounters;
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
+import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
+import com.android.systemui.statusbar.notification.shared.NotificationContentAlphaOptimization;
 import com.android.systemui.statusbar.notification.stack.AmbientState;
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
@@ -218,6 +220,7 @@
     private boolean mShowingPublic;
     private boolean mSensitive;
     private boolean mSensitiveHiddenInGeneral;
+    private boolean mShowPublicExpander = true;
     private boolean mShowingPublicInitialized;
     private boolean mHideSensitiveForIntrinsicHeight;
     private float mHeaderVisibleAmount = DEFAULT_HEADER_VISIBLE_AMOUNT;
@@ -586,7 +589,11 @@
             mMenuRow.setAppName(mAppName);
         }
         if (mIsSummaryWithChildren) {
-            mChildrenContainer.recreateNotificationHeader(mExpandClickListener, isConversation());
+            if (!AsyncGroupHeaderViewInflation.isEnabled()) {
+                // We create the header from the background thread instead
+                mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
+                        isConversation());
+            }
             mChildrenContainer.onNotificationUpdated();
         }
         if (mAnimationRunning) {
@@ -599,8 +606,7 @@
             mNotificationParent.updateChildrenAppearance();
         }
         onAttachedChildrenCountChanged();
-        // The public layouts expand button is always visible
-        mPublicLayout.updateExpandButtons(true);
+        mPublicLayout.updateExpandButtons(mShowPublicExpander);
         updateLimits();
         updateShelfIconColor();
         if (mUpdateSelfBackgroundOnUpdate) {
@@ -668,7 +674,9 @@
 
     public int getOriginalIconColor() {
         if (mIsSummaryWithChildren && !shouldShowPublic()) {
-            return mChildrenContainer.getVisibleWrapper().getOriginalIconColor();
+            if (!AsyncGroupHeaderViewInflation.isEnabled()) {
+                return mChildrenContainer.getVisibleWrapper().getOriginalIconColor();
+            }
         }
         int color = getShowingLayout().getOriginalIconColor();
         if (color != Notification.COLOR_INVALID) {
@@ -1513,6 +1521,40 @@
         return mChildrenContainer;
     }
 
+    /**
+     * @return An non-null instance of mChildrenContainer, inflate it if not yet.
+     */
+    public @NonNull NotificationChildrenContainer getChildrenContainerNonNull() {
+        if (mChildrenContainer == null) {
+            mChildrenContainerStub.inflate();
+        }
+        return mChildrenContainer;
+    }
+
+    /**
+     * Set the group notification header view
+     * @param headerView header view to set
+     */
+    public void setGroupHeader(NotificationHeaderView headerView) {
+        NotificationChildrenContainer childrenContainer = getChildrenContainerNonNull();
+        childrenContainer.setGroupHeader(
+                /* headerView= */ headerView,
+                /* onClickListener= */ mExpandClickListener
+        );
+    }
+
+    /**
+     * Set the low-priority group notification header view
+     * @param headerView header view to set
+     */
+    public void setLowPriorityGroupHeader(NotificationHeaderView headerView) {
+        NotificationChildrenContainer childrenContainer = getChildrenContainerNonNull();
+        childrenContainer.setLowPriorityGroupHeader(
+                /* headerViewLowPriority= */ headerView,
+                /* onClickListener= */ mExpandClickListener
+        );
+    }
+
     public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
         boolean wasAboveShelf = isAboveShelf();
         boolean changed = headsUpAnimatingAway != mHeadsupDisappearRunning;
@@ -1565,7 +1607,11 @@
     @Override
     public View getShelfTransformationTarget() {
         if (mIsSummaryWithChildren && !shouldShowPublic()) {
-            return mChildrenContainer.getVisibleWrapper().getShelfTransformationTarget();
+            NotificationViewWrapper viewWrapper = mChildrenContainer.getVisibleWrapper();
+            if (AsyncGroupHeaderViewInflation.isEnabled() && viewWrapper == null) {
+                return null;
+            }
+            return viewWrapper.getShelfTransformationTarget();
         }
         return getShowingLayout().getShelfTransformationTarget();
     }
@@ -1715,7 +1761,7 @@
      * Constructs an ExpandableNotificationRow. Used by layout inflation.
      *
      * @param context passed to image resolver
-     * @param attrs attributes used to initialize parent view
+     * @param attrs   attributes used to initialize parent view
      */
     public ExpandableNotificationRow(Context context, AttributeSet attrs) {
         this(context, attrs, context);
@@ -1729,9 +1775,9 @@
      * AsyncLayoutFactory} in {@link RowInflaterTask}.
      *
      * @param context context context of the view
-     * @param attrs attributes used to initialize parent view
-     * @param entry notification that the row will be associated to (determines the user for the
-     *              ImageResolver)
+     * @param attrs   attributes used to initialize parent view
+     * @param entry   notification that the row will be associated to (determines the user for the
+     *                ImageResolver)
      */
     public ExpandableNotificationRow(Context context, AttributeSet attrs, NotificationEntry entry) {
         this(context, attrs, userContextForEntry(context, entry));
@@ -1982,7 +2028,7 @@
             return traceTag;
         }
 
-        return  traceTag + "(" + getEntry().getNotificationStyle() + ")";
+        return traceTag + "(" + getEntry().getNotificationStyle() + ")";
     }
 
     @Override
@@ -2710,10 +2756,12 @@
                 && mChildrenContainer.getNotificationChildCount() > 0;
         if (mIsSummaryWithChildren) {
             Trace.beginSection("ExpNotRow#onChildCountChanged (summary)");
-            NotificationViewWrapper wrapper = mChildrenContainer.getNotificationViewWrapper();
-            if (wrapper == null || wrapper.getNotificationHeader() == null) {
-                mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
-                        isConversation());
+            if (!AsyncGroupHeaderViewInflation.isEnabled()) {
+                NotificationViewWrapper wrapper = mChildrenContainer.getNotificationViewWrapper();
+                if (wrapper == null || wrapper.getNotificationHeader() == null) {
+                    mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
+                            isConversation());
+                }
             }
         }
         if (!mIsSummaryWithChildren && wasSummary) {
@@ -2837,6 +2885,14 @@
         }
     }
 
+    /** Sets whether this notification row should show the notification expander or not */
+    public void setPublicExpanderVisible(boolean showPublicExpander) {
+        if (mShowPublicExpander != showPublicExpander) {
+            mShowPublicExpander = showPublicExpander;
+            mPublicLayout.updateExpandButtons(mShowPublicExpander);
+        }
+    }
+
     @Override
     public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
         mHideSensitiveForIntrinsicHeight = hideSensitive;
@@ -2863,6 +2919,7 @@
         if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
             return;
         }
+        float oldAlpha = getContentView().getAlpha();
 
         if (!animated) {
             mPublicLayout.animate().cancel();
@@ -2873,6 +2930,13 @@
             resetAllContentAlphas();
             mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
             updateChildrenVisibility();
+            if (NotificationContentAlphaOptimization.isEnabled()) {
+                // We want to set the old alpha to the now-showing layout to avoid breaking an
+                // on-going animation
+                if (oldAlpha != 1f) {
+                    setAlphaAndLayerType(mShowingPublic ? mPublicLayout : mPrivateLayout, oldAlpha);
+                }
+            }
         } else {
             animateShowingPublic(delay, duration, mShowingPublic);
         }
@@ -3019,6 +3083,7 @@
                             onStartedRunnable.run();
                         }
                     }
+
                     @Override
                     public void onAnimationEnd(Animator animation) {
                         ExpandableNotificationRow.super.performRemoveAnimation(
@@ -3713,6 +3778,9 @@
             pw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
             pw.print(", mShowNoBackground: " + mShowNoBackground);
             pw.println();
+            if (NotificationContentView.INCLUDE_HEIGHTS_TO_DUMP) {
+                dumpHeights(pw);
+            }
             showingLayout.dump(pw, args);
 
             if (getViewState() != null) {
@@ -3756,6 +3824,34 @@
         });
     }
 
+    private void dumpHeights(IndentingPrintWriter pw) {
+        pw.print("Heights: ");
+        pw.print("intrinsic", getIntrinsicHeight());
+        pw.print("actual", getActualHeight());
+        pw.print("maxContent", getMaxContentHeight());
+        pw.print("maxExpanded", getMaxExpandHeight());
+        pw.print("collapsed", getCollapsedHeight());
+        pw.print("headsup", getHeadsUpHeight());
+        pw.print("headsup  without header", getHeadsUpHeightWithoutHeader());
+        pw.print("minHeight", getMinHeight());
+        pw.print("pinned headsup", getPinnedHeadsUpHeight(
+                true /* atLeastMinHeight */));
+        pw.println();
+        pw.print("Intrinsic Height Factors: ");
+        pw.print("isUserLocked()", isUserLocked());
+        pw.print("isChildInGroup()", isChildInGroup());
+        pw.print("isGroupExpanded()", isGroupExpanded());
+        pw.print("sensitive", mSensitive);
+        pw.print("hideSensitiveForIntrinsicHeight", mHideSensitiveForIntrinsicHeight);
+        pw.print("isSummaryWithChildren", mIsSummaryWithChildren);
+        pw.print("canShowHeadsUp()", canShowHeadsUp());
+        pw.print("isHeadsUpState()", isHeadsUpState());
+        pw.print("isPinned()", isPinned());
+        pw.print("headsupDisappearRunning", mHeadsupDisappearRunning);
+        pw.print("isExpanded()", isExpanded());
+        pw.println();
+    }
+
     private void logKeepInParentChildDetached(ExpandableNotificationRow child) {
         if (mLogger != null) {
             mLogger.logKeepInParentChildDetached(child.getEntry(), getEntry());
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 e288e85..d308fa5 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
@@ -37,7 +37,9 @@
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.util.Log;
+import android.view.NotificationHeaderView;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.RemoteViews;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -51,11 +53,13 @@
 import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
 import com.android.systemui.statusbar.notification.InflationException;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
 import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation;
 import com.android.systemui.statusbar.notification.row.ui.viewbinder.SingleLineConversationViewBinder;
 import com.android.systemui.statusbar.notification.row.ui.viewbinder.SingleLineViewBinder;
 import com.android.systemui.statusbar.notification.row.ui.viewmodel.SingleLineViewModel;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
+import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder;
@@ -387,6 +391,21 @@
             logger.logAsyncTaskProgress(entryForLogging, "creating public remote view");
             result.newPublicView = builder.makePublicContentView(isLowPriority);
         }
+
+        if (AsyncGroupHeaderViewInflation.isEnabled()) {
+            if ((reInflateFlags & FLAG_GROUP_SUMMARY_HEADER) != 0) {
+                logger.logAsyncTaskProgress(entryForLogging,
+                        "creating group summary remote view");
+                result.mNewGroupHeaderView = builder.makeNotificationGroupHeader();
+            }
+
+            if ((reInflateFlags & FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER) != 0) {
+                logger.logAsyncTaskProgress(entryForLogging,
+                        "creating low-priority group summary remote view");
+                result.mNewLowPriorityGroupHeaderView =
+                        builder.makeLowPriorityContentView(true /* useRegularSubtext */);
+            }
+        }
         setNotifsViewsInflaterFactory(result, row, notifLayoutInflaterFactoryProvider);
         result.packageContext = packageContext;
         result.headsUpStatusBarText = builder.getHeadsUpStatusBarText(false /* showingPublic */);
@@ -534,6 +553,67 @@
                     runningInflations, applyCallback, logger);
         }
 
+        if (AsyncGroupHeaderViewInflation.isEnabled()) {
+            NotificationChildrenContainer childrenContainer = row.getChildrenContainerNonNull();
+            if ((reInflateFlags & FLAG_GROUP_SUMMARY_HEADER) != 0) {
+                boolean isNewView =
+                        !canReapplyRemoteView(
+                                /* newView = */ result.mNewGroupHeaderView,
+                                /* oldView = */ remoteViewCache
+                                        .getCachedView(entry, FLAG_GROUP_SUMMARY_HEADER));
+                ApplyCallback applyCallback = new ApplyCallback() {
+                    @Override
+                    public void setResultView(View v) {
+                        logger.logAsyncTaskProgress(entry, "group header view applied");
+                        result.mInflatedGroupHeaderView = (NotificationHeaderView) v;
+                    }
+
+                    @Override
+                    public RemoteViews getRemoteView() {
+                        return result.mNewGroupHeaderView;
+                    }
+                };
+                logger.logAsyncTaskProgress(entry, "applying group header view");
+                applyRemoteView(inflationExecutor, inflateSynchronously, result, reInflateFlags,
+                        /* inflationId = */ FLAG_GROUP_SUMMARY_HEADER,
+                        remoteViewCache, entry, row, isNewView, remoteViewClickHandler, callback,
+                        /* parentLayout = */ childrenContainer,
+                        /* existingView = */ childrenContainer.getNotificationHeader(),
+                        /* existingWrapper = */ childrenContainer.getNotificationHeaderWrapper(),
+                        runningInflations, applyCallback, logger);
+            }
+
+            if ((reInflateFlags & FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER) != 0) {
+                boolean isNewView =
+                        !canReapplyRemoteView(
+                                /* newView = */ result.mNewLowPriorityGroupHeaderView,
+                                /* oldView = */ remoteViewCache.getCachedView(
+                                        entry, FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER));
+                ApplyCallback applyCallback = new ApplyCallback() {
+                    @Override
+                    public void setResultView(View v) {
+                        logger.logAsyncTaskProgress(entry,
+                                "low-priority group header view applied");
+                        result.mInflatedLowPriorityGroupHeaderView = (NotificationHeaderView) v;
+                    }
+
+                    @Override
+                    public RemoteViews getRemoteView() {
+                        return result.mNewLowPriorityGroupHeaderView;
+                    }
+                };
+                logger.logAsyncTaskProgress(entry, "applying low priority group header view");
+                applyRemoteView(inflationExecutor, inflateSynchronously, result, reInflateFlags,
+                        /* inflationId = */ FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER,
+                        remoteViewCache, entry, row, isNewView, remoteViewClickHandler, callback,
+                        /* parentLayout = */ childrenContainer,
+                        /* existingView = */ childrenContainer.getNotificationHeaderLowPriority(),
+                        /* existingWrapper = */ childrenContainer
+                                .getLowPriorityViewWrapper(),
+                        runningInflations, applyCallback, logger);
+            }
+        }
+
         // Let's try to finish, maybe nobody is even inflating anything
         finishIfDone(result, reInflateFlags, remoteViewCache, runningInflations, callback, entry,
                 row, logger);
@@ -560,7 +640,7 @@
             boolean isNewView,
             RemoteViews.InteractionHandler remoteViewClickHandler,
             @Nullable final InflationCallback callback,
-            NotificationContentView parentLayout,
+            ViewGroup parentLayout,
             View existingView,
             NotificationViewWrapper existingWrapper,
             final HashMap<Integer, CancellationSignal> runningInflations,
@@ -702,6 +782,10 @@
         return result;
     }
 
+    /**
+     * Notifications with undecorated custom views need to satisfy a minimum height to avoid visual
+     * issues.
+     */
     private static boolean requiresHeightCheck(NotificationEntry entry) {
         // Undecorated custom views are disallowed from S onwards
         if (entry.targetSdk >= Build.VERSION_CODES.S) {
@@ -845,6 +929,39 @@
                 }
             }
 
+            if (AsyncGroupHeaderViewInflation.isEnabled()) {
+                if ((reInflateFlags & FLAG_GROUP_SUMMARY_HEADER) != 0) {
+                    if (result.mInflatedGroupHeaderView != null) {
+                        row.setIsLowPriority(false);
+                        row.setGroupHeader(/* headerView= */ result.mInflatedGroupHeaderView);
+                        remoteViewCache.putCachedView(entry, FLAG_GROUP_SUMMARY_HEADER,
+                                result.mNewGroupHeaderView);
+                    } else if (remoteViewCache.hasCachedView(entry, FLAG_GROUP_SUMMARY_HEADER)) {
+                        // Re-inflation case. Only update if it's still cached (i.e. view has not
+                        // been freed while inflating).
+                        remoteViewCache.putCachedView(entry, FLAG_GROUP_SUMMARY_HEADER,
+                                result.mNewGroupHeaderView);
+                    }
+                }
+
+                if ((reInflateFlags & FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER) != 0) {
+                    if (result.mInflatedLowPriorityGroupHeaderView != null) {
+                        // New view case, set row to low priority
+                        row.setIsLowPriority(true);
+                        row.setLowPriorityGroupHeader(
+                                /* headerView= */ result.mInflatedLowPriorityGroupHeaderView);
+                        remoteViewCache.putCachedView(entry, FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER,
+                                result.mNewLowPriorityGroupHeaderView);
+                    } else if (remoteViewCache.hasCachedView(entry,
+                            FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER)) {
+                        // Re-inflation case. Only update if it's still cached (i.e. view has not
+                        // been freed while inflating).
+                        remoteViewCache.putCachedView(entry, FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER,
+                                result.mNewGroupHeaderView);
+                    }
+                }
+            }
+
             entry.headsUpStatusBarText = result.headsUpStatusBarText;
             entry.headsUpStatusBarTextPublic = result.headsUpStatusBarTextPublic;
             if (endListener != null) {
@@ -1147,6 +1264,8 @@
         private RemoteViews newHeadsUpView;
         private RemoteViews newExpandedView;
         private RemoteViews newPublicView;
+        private RemoteViews mNewGroupHeaderView;
+        private RemoteViews mNewLowPriorityGroupHeaderView;
 
         @VisibleForTesting
         Context packageContext;
@@ -1155,6 +1274,8 @@
         private View inflatedHeadsUpView;
         private View inflatedExpandedView;
         private View inflatedPublicView;
+        private NotificationHeaderView mInflatedGroupHeaderView;
+        private NotificationHeaderView mInflatedLowPriorityGroupHeaderView;
         private CharSequence headsUpStatusBarText;
         private CharSequence headsUpStatusBarTextPublic;
 
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
index ee9462c..15c7055 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterLogger.kt
@@ -27,6 +27,8 @@
 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.FLAG_CONTENT_VIEW_SINGLE_LINE
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_GROUP_SUMMARY_HEADER
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag
 import javax.inject.Inject
 
@@ -145,6 +147,12 @@
             if (flag and FLAG_CONTENT_VIEW_SINGLE_LINE != 0) {
                 l.add("SINGLE_LINE")
             }
+            if (flag and FLAG_GROUP_SUMMARY_HEADER != 0) {
+                l.add("GROUP_SUMMARY_HEADER")
+            }
+            if (flag and FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER != 0) {
+                l.add("LOW_PRIORITY_GROUP_SUMMARY_HEADER")
+            }
             return l.joinToString("|")
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 3742482..137e1b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -70,6 +70,7 @@
 import com.android.systemui.statusbar.policy.SmartReplyView;
 import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
 import com.android.systemui.util.Compile;
+import com.android.systemui.util.DumpUtilsKt;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -97,6 +98,8 @@
 
     private static final int UNDEFINED = -1;
 
+    protected static final boolean INCLUDE_HEIGHTS_TO_DUMP = true;
+
     private final Rect mClipBounds = new Rect();
 
     private int mMinContractedHeight;
@@ -238,7 +241,10 @@
         mMinContractedHeight = getResources().getDimensionPixelSize(
                 R.dimen.min_notification_layout_height);
         if (AsyncHybridViewInflation.isEnabled()) {
-            //TODO: set the height with a more reasonable min single-line height
+            //TODO (b/217799515): single-line view height is the greater of two heights: text view
+            // height and icon height (when there's an icon). icon height is fixed to be
+            // conversation_single_line_face_pile_size (24dp), the text view's height is 16sp,
+            // its pixel height changes with the system's font scaling factor.
             mMinSingleLineHeight = getResources().getDimensionPixelSize(
                     R.dimen.conversation_single_line_face_pile_size);
         }
@@ -843,7 +849,7 @@
                 if (mSingleLineView != null) {
                     return getViewHeight(VISIBLE_TYPE_SINGLELINE);
                 } else {
-                    Log.wtf(TAG, "getMinHeight: mSingleLineView == null");
+                    //TODO(b/217799515): investigate the impact of min-height value
                     return mMinSingleLineHeight;
                 }
             } else {
@@ -2193,6 +2199,11 @@
             pw.print("null");
         }
         pw.println();
+
+        if (INCLUDE_HEIGHTS_TO_DUMP) {
+            dumpContentDimensions(DumpUtilsKt.asIndenting(pw));
+        }
+
         pw.println("mBubblesEnabledForUser: " + mBubblesEnabledForUser);
 
         pw.print("RemoteInputViews { ");
@@ -2213,6 +2224,69 @@
         pw.println(" }");
     }
 
+    private String visibleTypeToString(int visibleType) {
+        return switch (visibleType) {
+            case VISIBLE_TYPE_CONTRACTED -> "CONTRACTED";
+            case VISIBLE_TYPE_EXPANDED -> "EXPANDED";
+            case VISIBLE_TYPE_HEADSUP -> "HEADSUP";
+            case VISIBLE_TYPE_SINGLELINE -> "SINGLELINE";
+            default -> "NONE";
+        };
+    }
+
+    /** Add content views to dump */
+    private void dumpContentDimensions(IndentingPrintWriter pw) {
+        pw.print("ContentDimensions: ");
+        pw.print("visibleType(String)", visibleTypeToString(mVisibleType));
+        pw.print("measured width", getMeasuredWidth());
+        pw.print("measured height", getMeasuredHeight());
+        pw.print("maxHeight", getMaxHeight());
+        pw.print("minHeight", getMinHeight());
+        pw.println();
+        pw.println("ChildViews:");
+        DumpUtilsKt.withIncreasedIndent(pw, () -> {
+            final View contractedChild = mContractedChild;
+            if (contractedChild != null) {
+                dumpChildViewDimensions(pw, contractedChild, "Contracted Child:");
+                pw.println();
+            }
+
+            final View expandedChild = mExpandedChild;
+            if (expandedChild != null) {
+                dumpChildViewDimensions(pw, expandedChild, "Expanded Child:");
+                pw.println();
+            }
+
+            final View headsUpChild = mHeadsUpChild;
+            if (headsUpChild != null) {
+                dumpChildViewDimensions(pw, headsUpChild, "HeadsUp Child:");
+                pw.println();
+            }
+            final View singleLineView = mSingleLineView;
+            if (singleLineView != null) {
+                dumpChildViewDimensions(pw, singleLineView, "Single Line  View:");
+                pw.println();
+            }
+
+        });
+        final int expandedRemoteInputHeight = getExtraRemoteInputHeight(mExpandedRemoteInput);
+        final int headsUpRemoteInputHeight = getExtraRemoteInputHeight(mHeadsUpRemoteInput);
+        pw.print("expandedRemoteInputHeight", expandedRemoteInputHeight);
+        pw.print("headsUpRemoteInputHeight", headsUpRemoteInputHeight);
+        pw.println();
+    }
+
+    private void dumpChildViewDimensions(IndentingPrintWriter pw, View view,
+            String name) {
+        pw.print(name + " ");
+        DumpUtilsKt.withIncreasedIndent(pw, () -> {
+            pw.print("width", view.getWidth());
+            pw.print("height", view.getHeight());
+            pw.print("measuredWidth", view.getMeasuredWidth());
+            pw.print("measuredHeight", view.getMeasuredHeight());
+        });
+    }
+
     /** Add any existing SmartReplyView to the dump */
     public void dumpSmartReplies(IndentingPrintWriter pw) {
         if (mHeadsUpSmartReplyView != null) {
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 736140c..b0fd475 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
@@ -81,6 +81,8 @@
                     FLAG_CONTENT_VIEW_HEADS_UP,
                     FLAG_CONTENT_VIEW_PUBLIC,
                     FLAG_CONTENT_VIEW_SINGLE_LINE,
+                    FLAG_GROUP_SUMMARY_HEADER,
+                    FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER,
                     FLAG_CONTENT_VIEW_ALL})
     @interface InflationFlag {}
     /**
@@ -108,7 +110,17 @@
      */
     int FLAG_CONTENT_VIEW_SINGLE_LINE = 1 << 4;
 
-    int FLAG_CONTENT_VIEW_ALL = (1 << 5) - 1;
+    /**
+     * The notification group summary header view
+     */
+    int FLAG_GROUP_SUMMARY_HEADER = 1 << 5;
+
+    /**
+     * The notification low-priority group summary header view
+     */
+    int FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER = 1 << 6;
+
+    int FLAG_CONTENT_VIEW_ALL = (1 << 7) - 1;
 
     /**
      * Parameters for content view binding
@@ -129,6 +141,11 @@
          * Use increased height when binding heads up views.
          */
         public boolean usesIncreasedHeadsUpHeight;
+
+        /**
+         * Is group summary notification
+         */
+        public boolean mIsGroupSummary;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationContentAlphaOptimization.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationContentAlphaOptimization.kt
new file mode 100644
index 0000000..c703595
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationContentAlphaOptimization.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.shared
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the Async Group Header Inflation flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object NotificationContentAlphaOptimization {
+    /** The aconfig flag name */
+    const val FLAG_NAME = Flags.FLAG_NOTIFICATION_CONTENT_ALPHA_OPTIMIZATION
+
+    /** A token used for dependency declaration */
+    val token: FlagToken
+        get() = FlagToken(FLAG_NAME, isEnabled)
+
+    /** Is the async inflation of group header views enabled */
+    @JvmStatic
+    inline val isEnabled
+        get() = Flags.notificationContentAlphaOptimization()
+
+    /**
+     * Called to ensure code is only run when the flag is enabled. This protects users from the
+     * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+     * build to ensure that the refactor author catches issues in testing.
+     */
+    @JvmStatic
+    inline fun isUnexpectedlyInLegacyMode() =
+        RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+    /**
+     * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+     * the flag is enabled to ensure that the refactor author catches issues in testing.
+     */
+    @JvmStatic
+    inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index abf6c27..fa97300 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -55,6 +55,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 import com.android.systemui.statusbar.notification.row.HybridGroupManager;
 import com.android.systemui.statusbar.notification.row.HybridNotificationView;
+import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 
@@ -131,6 +132,7 @@
     private int mUntruncatedChildCount;
     private boolean mContainingNotificationIsFaded = false;
     private RoundableState mRoundableState;
+    private int mMinSingleLineHeight;
 
     private NotificationChildrenContainerLogger mLogger;
 
@@ -183,6 +185,8 @@
                 com.android.internal.R.dimen.notification_content_margin)
                 - mNotificationHeaderMargin;
         mHybridGroupManager.initDimens();
+        mMinSingleLineHeight = getResources().getDimensionPixelSize(
+                R.dimen.conversation_single_line_face_pile_size);
     }
 
     @NonNull
@@ -385,16 +389,31 @@
         return mAttachedChildren.size();
     }
 
-    public void recreateNotificationHeader(OnClickListener listener, boolean isConversation) {
+    /**
+     * Re-create the Notification header view
+     * @param listener OnClickListener of the header view
+     * @param isConversation if the notification group is a conversation group
+     */
+    public void recreateNotificationHeader(
+            OnClickListener listener,
+            boolean isConversation
+    ) {
+        // We don't want to inflate headers from the main thread when async inflation enabled
+        AsyncGroupHeaderViewInflation.assertInLegacyMode();
+        // TODO(b/217799515): remove traces from this function in a follow-up change
         Trace.beginSection("NotifChildCont#recreateHeader");
         mHeaderClickListener = listener;
         mIsConversation = isConversation;
         StatusBarNotification notification = mContainingNotification.getEntry().getSbn();
         final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
                 notification.getNotification());
+        Trace.beginSection("recreateHeader#makeNotificationGroupHeader");
         RemoteViews header = builder.makeNotificationGroupHeader();
+        Trace.endSection();
         if (mNotificationHeader == null) {
+            Trace.beginSection("recreateHeader#apply");
             mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
+            Trace.endSection();
             mNotificationHeader.findViewById(com.android.internal.R.id.expand_button)
                     .setVisibility(VISIBLE);
             mNotificationHeader.setOnClickListener(mHeaderClickListener);
@@ -407,7 +426,9 @@
             addView(mNotificationHeader, 0);
             invalidate();
         } else {
+            Trace.beginSection("recreateHeader#reapply");
             header.reapply(getContext(), mNotificationHeader);
+            Trace.endSection();
         }
         mNotificationHeaderWrapper.setExpanded(mChildrenExpanded);
         mNotificationHeaderWrapper.onContentUpdated(mContainingNotification);
@@ -417,12 +438,105 @@
         Trace.endSection();
     }
 
+    private void removeGroupHeader() {
+        if (mNotificationHeader == null) {
+            return;
+        }
+        removeView(mNotificationHeader);
+        mNotificationHeader = null;
+        mNotificationHeaderWrapper = null;
+    }
+
+    private void removeLowPriorityGroupHeader() {
+        if (mNotificationHeaderLowPriority == null) {
+            return;
+        }
+        removeView(mNotificationHeaderLowPriority);
+        mNotificationHeaderLowPriority = null;
+        mNotificationHeaderWrapperLowPriority = null;
+    }
+
+    /**
+     * Set the group header view
+     * @param headerView view to set
+     * @param onClickListener OnClickListener of the header view
+     */
+    public void setGroupHeader(
+            NotificationHeaderView headerView,
+            OnClickListener onClickListener
+    ) {
+        if (AsyncGroupHeaderViewInflation.isUnexpectedlyInLegacyMode()) return;
+        mHeaderClickListener = onClickListener;
+
+        removeGroupHeader();
+
+        if (headerView == null) {
+            return;
+        }
+
+        mNotificationHeader = headerView;
+        mNotificationHeader.findViewById(com.android.internal.R.id.expand_button)
+                .setVisibility(VISIBLE);
+        mNotificationHeader.setOnClickListener(mHeaderClickListener);
+        mNotificationHeaderWrapper =
+                (NotificationHeaderViewWrapper) NotificationViewWrapper.wrap(
+                        getContext(),
+                        mNotificationHeader,
+                        mContainingNotification);
+        mNotificationHeaderWrapper.setOnRoundnessChangedListener(this::invalidate);
+        addView(mNotificationHeader, 0);
+        invalidate();
+
+        mNotificationHeaderWrapper.setExpanded(mChildrenExpanded);
+        mNotificationHeaderWrapper.onContentUpdated(mContainingNotification);
+
+        updateHeaderVisibility(false /* animate */);
+        updateChildrenAppearance();
+
+        Trace.endSection();
+    }
+
+    /**
+     * Set the low-priority group header view
+     * @param headerViewLowPriority header view to set
+     * @param onClickListener OnClickListener of the header view
+     */
+    public void setLowPriorityGroupHeader(
+            NotificationHeaderView headerViewLowPriority,
+            OnClickListener onClickListener
+    ) {
+        if (AsyncGroupHeaderViewInflation.isUnexpectedlyInLegacyMode()) return;
+        removeLowPriorityGroupHeader();
+        if (headerViewLowPriority == null) {
+            return;
+        }
+
+        mNotificationHeaderLowPriority = headerViewLowPriority;
+        mNotificationHeaderLowPriority.findViewById(com.android.internal.R.id.expand_button)
+                .setVisibility(VISIBLE);
+        mNotificationHeaderLowPriority.setOnClickListener(onClickListener);
+        mNotificationHeaderWrapperLowPriority =
+                (NotificationHeaderViewWrapper) NotificationViewWrapper.wrap(
+                        getContext(),
+                        mNotificationHeaderLowPriority,
+                        mContainingNotification);
+        mNotificationHeaderWrapperLowPriority.setOnRoundnessChangedListener(this::invalidate);
+        addView(mNotificationHeaderLowPriority, 0);
+        invalidate();
+
+        mNotificationHeaderWrapperLowPriority.onContentUpdated(mContainingNotification);
+        updateHeaderVisibility(false /* animate */);
+        updateChildrenAppearance();
+    }
+
     /**
      * Recreate the low-priority header.
      *
      * @param builder a builder to reuse. Otherwise the builder will be recovered.
      */
-    private void recreateLowPriorityHeader(Notification.Builder builder, boolean isConversation) {
+    @VisibleForTesting
+    void recreateLowPriorityHeader(Notification.Builder builder, boolean isConversation) {
+        AsyncGroupHeaderViewInflation.assertInLegacyMode();
         RemoteViews header;
         StatusBarNotification notification = mContainingNotification.getEntry().getSbn();
         if (mIsLowPriority) {
@@ -527,8 +641,10 @@
      * @param alpha alpha value to apply to the content
      */
     public void setContentAlpha(float alpha) {
-        for (int i = 0; i < mNotificationHeader.getChildCount(); i++) {
-            mNotificationHeader.getChildAt(i).setAlpha(alpha);
+        if (mNotificationHeader != null) {
+            for (int i = 0; i < mNotificationHeader.getChildCount(); i++) {
+                mNotificationHeader.getChildAt(i).setAlpha(alpha);
+            }
         }
         for (ExpandableNotificationRow child : getAttachedChildren()) {
             child.setContentAlpha(alpha);
@@ -564,7 +680,11 @@
      */
     private int getIntrinsicHeight(float maxAllowedVisibleChildren) {
         if (showingAsLowPriority()) {
-            return mNotificationHeaderLowPriority.getHeight();
+            if (AsyncGroupHeaderViewInflation.isEnabled()) {
+                return mHeaderHeight;
+            } else {
+                return mNotificationHeaderLowPriority.getHeight();
+            }
         }
         int intrinsicHeight = mNotificationHeaderMargin + mCurrentHeaderTranslation;
         int visibleChildren = 0;
@@ -1023,6 +1143,14 @@
         return mCurrentHeader;
     }
 
+    public NotificationHeaderView getNotificationHeader() {
+        return mNotificationHeader;
+    }
+
+    public NotificationHeaderView getNotificationHeaderLowPriority() {
+        return mNotificationHeaderLowPriority;
+    }
+
     private void updateHeaderVisibility(boolean animate) {
         ViewGroup desiredHeader;
         ViewGroup currentHeader = mCurrentHeader;
@@ -1032,6 +1160,10 @@
             return;
         }
 
+        if (AsyncGroupHeaderViewInflation.isEnabled() && desiredHeader == null) {
+            return;
+        }
+
         if (animate) {
             if (desiredHeader != null && currentHeader != null) {
                 currentHeader.setVisibility(VISIBLE);
@@ -1271,6 +1403,9 @@
             boolean likeHighPriority,
             int headerTranslation) {
         if (!likeHighPriority && showingAsLowPriority()) {
+            if (AsyncGroupHeaderViewInflation.isEnabled()) {
+                return mHeaderHeight;
+            }
             if (mNotificationHeaderLowPriority == null) {
                 Log.e(TAG, "getMinHeight: low priority header is null", new Exception());
                 return 0;
@@ -1295,8 +1430,12 @@
             if (singleLineView != null) {
                 minExpandHeight += singleLineView.getHeight();
             } else {
-                Log.e(TAG, "getMinHeight: child " + child.getEntry().getKey()
-                                + " single line view is null", new Exception());
+                if (AsyncGroupHeaderViewInflation.isEnabled()) {
+                    minExpandHeight += mMinSingleLineHeight;
+                } else {
+                    Log.e(TAG, "getMinHeight: child " + child.getEntry().getKey()
+                            + " single line view is null", new Exception());
+                }
             }
             visibleChildren++;
         }
@@ -1309,15 +1448,19 @@
     }
 
     public void reInflateViews(OnClickListener listener, StatusBarNotification notification) {
-        if (mNotificationHeader != null) {
-            removeView(mNotificationHeader);
-            mNotificationHeader = null;
+        if (!AsyncGroupHeaderViewInflation.isEnabled()) {
+            // When Async header inflation is enabled, we do not reinflate headers because they are
+            // inflated from the background thread
+            if (mNotificationHeader != null) {
+                removeView(mNotificationHeader);
+                mNotificationHeader = null;
+            }
+            if (mNotificationHeaderLowPriority != null) {
+                removeView(mNotificationHeaderLowPriority);
+                mNotificationHeaderLowPriority = null;
+            }
+            recreateNotificationHeader(listener, mIsConversation);
         }
-        if (mNotificationHeaderLowPriority != null) {
-            removeView(mNotificationHeaderLowPriority);
-            mNotificationHeaderLowPriority = null;
-        }
-        recreateNotificationHeader(listener, mIsConversation);
         initDimens();
         for (int i = 0; i < mDividers.size(); i++) {
             View prevDivider = mDividers.get(i);
@@ -1395,7 +1538,9 @@
     public void setIsLowPriority(boolean isLowPriority) {
         mIsLowPriority = isLowPriority;
         if (mContainingNotification != null) { /* we're not yet set up yet otherwise */
-            recreateLowPriorityHeader(null /* existingBuilder */, mIsConversation);
+            if (!AsyncGroupHeaderViewInflation.isEnabled()) {
+                recreateLowPriorityHeader(null /* existingBuilder */, mIsConversation);
+            }
             updateHeaderVisibility(false /* animate */);
         }
         if (mUserLocked) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index e397a70..27db84f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -124,6 +124,7 @@
 import com.android.systemui.statusbar.policy.SplitShadeStateController;
 import com.android.systemui.util.Assert;
 import com.android.systemui.util.ColorUtilKt;
+import com.android.systemui.util.Compile;
 import com.android.systemui.util.DumpUtilsKt;
 
 import com.google.errorprone.annotations.CompileTimeConstant;
@@ -150,6 +151,7 @@
     public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
     private static final String TAG = "StackScroller";
     private static final boolean SPEW = Log.isLoggable(TAG, Log.VERBOSE);
+    private static final boolean DEBUG_UPDATE_SIDE_PADDING = Compile.IS_DEBUG;
 
     private boolean mShadeNeedsToClose = false;
 
@@ -218,6 +220,7 @@
     int mBottomInset = 0;
     private float mQsExpansionFraction;
     private final int mSplitShadeMinContentHeight;
+    private String mLastUpdateSidePaddingDumpString;
 
     /**
      * The algorithm which calculates the properties for our children
@@ -316,6 +319,10 @@
             = new ViewTreeObserver.OnPreDrawListener() {
         @Override
         public boolean onPreDraw() {
+            if (SceneContainerFlag.isEnabled() && !mChildrenUpdateRequested) {
+                getViewTreeObserver().removeOnPreDrawListener(this);
+                return true;
+            }
             updateForcedScroll();
             updateChildren();
             mChildrenUpdateRequested = false;
@@ -677,7 +684,10 @@
                 res.getBoolean(R.bool.config_drawNotificationBackground);
         setOutlineProvider(mOutlineProvider);
 
-        boolean willDraw = mShouldDrawNotificationBackground || mDebugLines;
+        // We could set this whenever we 'requestChildUpdate' much like the viewTreeObserver, but
+        // that adds a bunch of complexity, and drawing nothing isn't *that* expensive.
+        boolean willDraw = SceneContainerFlag.isEnabled()
+                || mShouldDrawNotificationBackground || mDebugLines;
         setWillNotDraw(!willDraw);
         mBackgroundPaint.setAntiAlias(true);
         if (mDebugLines) {
@@ -813,7 +823,18 @@
         }
     }
 
+    private void onJustBeforeDraw() {
+        if (SceneContainerFlag.isEnabled()) {
+            if (mChildrenUpdateRequested) {
+                updateForcedScroll();
+                updateChildren();
+                mChildrenUpdateRequested = false;
+            }
+        }
+    }
+
     protected void onDraw(Canvas canvas) {
+        onJustBeforeDraw();
         if (mShouldDrawNotificationBackground
                 && (mSections[0].getCurrentBounds().top
                 < mSections[mSections.length - 1].getCurrentBounds().bottom
@@ -1106,15 +1127,28 @@
     }
 
     void updateSidePadding(int viewWidth) {
+        final boolean portrait =
+                getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
+
+        mLastUpdateSidePaddingDumpString = "viewWidth=" + viewWidth
+                + " skinnyNotifsInLandscape=" + mSkinnyNotifsInLandscape
+                + " portrait=" + portrait;
+
+        if (DEBUG_UPDATE_SIDE_PADDING) {
+            Log.v(TAG, "updateSidePadding: " + mLastUpdateSidePaddingDumpString);
+        }
+
         if (viewWidth == 0 || !mSkinnyNotifsInLandscape) {
             mSidePaddings = mMinimumPaddings;
             return;
         }
+
         // Portrait is easy, just use the dimen for paddings
-        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+        if (portrait) {
             mSidePaddings = mMinimumPaddings;
             return;
         }
+
         final int innerWidth = viewWidth - mMinimumPaddings * 2;
         final int qsTileWidth = (innerWidth - mQsTilePadding * 3) / 4;
         mSidePaddings = mMinimumPaddings + qsTileWidth + mQsTilePadding;
@@ -4992,6 +5026,17 @@
 
     public void generateHeadsUpAnimation(NotificationEntry entry, boolean isHeadsUp) {
         ExpandableNotificationRow row = entry.getHeadsUpAnimationView();
+        generateHeadsUpAnimation(row, isHeadsUp);
+    }
+
+    /**
+     * Notifies the NSSL, that the given view would need a HeadsUp animation, when it is being
+     * added to this container.
+     *
+     * @param row to animate
+     * @param isHeadsUp true for appear, false for disappear animations
+     */
+    public void generateHeadsUpAnimation(ExpandableNotificationRow row, boolean isHeadsUp) {
         final boolean add = mAnimationsEnabled && (isHeadsUp || mHeadsUpGoingAwayAnimationsAllowed);
         if (SPEW) {
             Log.v(TAG, "generateHeadsUpAnimation:"
@@ -5294,6 +5339,11 @@
             println(pw, "translationX", getTranslationX());
             println(pw, "translationY", getTranslationY());
             println(pw, "translationZ", getTranslationZ());
+            println(pw, "skinnyNotifsInLandscape", mSkinnyNotifsInLandscape);
+            println(pw, "minimumPaddings", mMinimumPaddings);
+            println(pw, "qsTilePadding", mQsTilePadding);
+            println(pw, "sidePaddings", mSidePaddings);
+            println(pw, "lastUpdateSidePadding", mLastUpdateSidePaddingDumpString);
             mNotificationStackSizeCalculator.dump(pw, args);
         });
         pw.println();
@@ -5725,11 +5775,17 @@
         mShelf.updateAppearance();
     }
 
-    void setTopHeadsUpRow(ExpandableNotificationRow topHeadsUpRow) {
+    /**
+     * @param topHeadsUpRow the first headsUp row in z-order.
+     */
+    public void setTopHeadsUpRow(ExpandableNotificationRow topHeadsUpRow) {
         mTopHeadsUpRow = topHeadsUpRow;
     }
 
-    void setNumHeadsUp(long numHeadsUp) {
+    /**
+     * @param numHeadsUp the number of active alerting notifications.
+     */
+    public void setNumHeadsUp(long numHeadsUp) {
         mNumHeadsUp = numHeadsUp;
         mAmbientState.setHasHeadsUpEntries(numHeadsUp > 0);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractor.kt
new file mode 100644
index 0000000..9cd46f5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractor.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.stack.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+
+/** Interactor exposing states related to the stack's context */
+@SysUISingleton
+class NotificationStackInteractor
+@Inject
+constructor(
+    keyguardInteractor: KeyguardInteractor,
+    powerInteractor: PowerInteractor,
+) {
+    val isShowingOnLockscreen: Flow<Boolean> =
+        combine(
+                // Non-notification UI elements of the notification list should not be visible
+                // on the lockscreen (incl. AOD and bouncer), except if the shade is opened on
+                // top. See b/219680200 for the footer and b/228790482, b/267060171 for the
+                // empty shade.
+                // TODO(b/323187006): There's a plan to eventually get rid of StatusBarState
+                //  entirely, so this will have to be replaced at some point.
+                keyguardInteractor.statusBarState.map { it == StatusBarState.KEYGUARD },
+                // The StatusBarState is unfortunately not updated quickly enough when the power
+                // button is pressed, so this is necessary in addition to the KEYGUARD check to
+                // cover the transition to AOD while going to sleep (b/190227875).
+                powerInteractor.isAsleep,
+            ) { (isOnKeyguard, isAsleep) ->
+                isOnKeyguard || isAsleep
+            }
+            .distinctUntilChanged()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
index 7b50256..c85a18a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
@@ -16,9 +16,6 @@
 
 package com.android.systemui.statusbar.notification.stack.ui.viewmodel
 
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.shared.model.StatusBarState
-import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.domain.interactor.RemoteInputInteractor
 import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
@@ -26,6 +23,7 @@
 import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
 import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModel
 import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.NotificationShelfViewModel
+import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackInteractor
 import com.android.systemui.statusbar.policy.domain.interactor.UserSetupInteractor
 import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
 import com.android.systemui.util.kotlin.combine
@@ -51,8 +49,7 @@
     val footer: Optional<FooterViewModel>,
     val logger: Optional<NotificationLoggerViewModel>,
     activeNotificationsInteractor: ActiveNotificationsInteractor,
-    keyguardInteractor: KeyguardInteractor,
-    powerInteractor: PowerInteractor,
+    notificationStackInteractor: NotificationStackInteractor,
     remoteInputInteractor: RemoteInputInteractor,
     seenNotificationsInteractor: SeenNotificationsInteractor,
     shadeInteractor: ShadeInteractor,
@@ -71,7 +68,7 @@
         } else {
             combine(
                     activeNotificationsInteractor.areAnyNotificationsPresent,
-                    isShowingOnLockscreen,
+                    notificationStackInteractor.isShowingOnLockscreen,
                 ) { hasNotifications, isShowingOnLockscreen ->
                     hasNotifications || !isShowingOnLockscreen
                 }
@@ -86,7 +83,7 @@
             combine(
                     activeNotificationsInteractor.areAnyNotificationsPresent,
                     shadeInteractor.isQsFullscreen,
-                    isShowingOnLockscreen,
+                    notificationStackInteractor.isShowingOnLockscreen,
                 ) { hasNotifications, isQsFullScreen, isShowingOnLockscreen ->
                     when {
                         hasNotifications -> false
@@ -109,7 +106,7 @@
             combine(
                     activeNotificationsInteractor.areAnyNotificationsPresent,
                     userSetupInteractor.isUserSetUp,
-                    isShowingOnLockscreen,
+                    notificationStackInteractor.isShowingOnLockscreen,
                     shadeInteractor.qsExpansion,
                     shadeInteractor.isQsFullscreen,
                     remoteInputInteractor.isRemoteInputActive,
@@ -177,29 +174,6 @@
         SHOW_WITH_ANIMATION(visible = true, canAnimate = true)
     }
 
-    private val isShowingOnLockscreen: Flow<Boolean> by lazy {
-        if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) {
-            flowOf(false)
-        } else {
-            combine(
-                    // Non-notification UI elements of the notification list should not be visible
-                    // on the lockscreen (incl. AOD and bouncer), except if the shade is opened on
-                    // top. See b/219680200 for the footer and b/228790482, b/267060171 for the
-                    // empty shade.
-                    // TODO(b/323187006): There's a plan to eventually get rid of StatusBarState
-                    //  entirely, so this will have to be replaced at some point.
-                    keyguardInteractor.statusBarState.map { it == StatusBarState.KEYGUARD },
-                    // The StatusBarState is unfortunately not updated quickly enough when the power
-                    // button is pressed, so this is necessary in addition to the KEYGUARD check to
-                    // cover the transition to AOD while going to sleep (b/190227875).
-                    powerInteractor.isAsleep,
-                ) { (isOnKeyguard, isAsleep) ->
-                    isOnKeyguard || isAsleep
-                }
-                .distinctUntilChanged()
-        }
-    }
-
     // TODO(b/308591475): This should be tracked separately by the empty shade.
     val areNotificationsHiddenInShade: Flow<Boolean> by lazy {
         if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModel.kt
index 3a0f03f..8d1cdfa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModel.kt
@@ -17,13 +17,15 @@
 
 package com.android.systemui.statusbar.notification.stack.ui.viewmodel
 
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.common.shared.model.NotificationContainerBounds
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
 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.scene.shared.model.Scenes
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackAppearanceInteractor
+import com.android.systemui.util.kotlin.FlowDumperImpl
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.StateFlow
@@ -35,10 +37,11 @@
 class NotificationStackAppearanceViewModel
 @Inject
 constructor(
+    dumpManager: DumpManager,
     stackAppearanceInteractor: NotificationStackAppearanceInteractor,
     shadeInteractor: ShadeInteractor,
     sceneInteractor: SceneInteractor,
-) {
+) : FlowDumperImpl(dumpManager) {
     /**
      * The expansion fraction of the notification stack. It should go from 0 to 1 when transitioning
      * from Gone to Shade scenes, and remain at 1 when in Lockscreen or Shade scenes and while
@@ -51,7 +54,7 @@
             ) { shadeExpansion, transitionState ->
                 when (transitionState) {
                     is ObservableTransitionState.Idle -> {
-                        if (transitionState.scene == SceneKey.Lockscreen) {
+                        if (transitionState.scene == Scenes.Lockscreen) {
                             1f
                         } else {
                             shadeExpansion
@@ -59,10 +62,10 @@
                     }
                     is ObservableTransitionState.Transition -> {
                         if (
-                            (transitionState.fromScene == SceneKey.Shade &&
-                                transitionState.toScene == SceneKey.QuickSettings) ||
-                                (transitionState.fromScene == SceneKey.QuickSettings &&
-                                    transitionState.toScene == SceneKey.Shade)
+                            (transitionState.fromScene == Scenes.Shade &&
+                                transitionState.toScene == Scenes.QuickSettings) ||
+                                (transitionState.fromScene == Scenes.QuickSettings &&
+                                    transitionState.toScene == Scenes.Shade)
                         ) {
                             1f
                         } else {
@@ -72,10 +75,12 @@
                 }
             }
             .distinctUntilChanged()
+            .dumpWhileCollecting("expandFraction")
 
     /** The bounds of the notification stack in the current scene. */
-    val stackBounds: Flow<NotificationContainerBounds> = stackAppearanceInteractor.stackBounds
+    val stackBounds: Flow<NotificationContainerBounds> =
+        stackAppearanceInteractor.stackBounds.dumpValue("stackBounds")
 
     /** The y-coordinate in px of top of the contents of the notification stack. */
-    val contentTop: StateFlow<Float> = stackAppearanceInteractor.contentTop
+    val contentTop: StateFlow<Float> = stackAppearanceInteractor.contentTop.dumpValue("contentTop")
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index 052e35c..f523793 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dump.DumpManager
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -60,6 +61,7 @@
 import com.android.systemui.keyguard.ui.viewmodel.ViewStateAccessor
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
+import com.android.systemui.util.kotlin.FlowDumperImpl
 import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -79,6 +81,7 @@
 import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.onStart
 import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.transformWhile
 import kotlinx.coroutines.isActive
 
 /** View-model for the shared notification container, used by both the shade and keyguard spaces */
@@ -87,9 +90,10 @@
 @Inject
 constructor(
     private val interactor: SharedNotificationContainerInteractor,
+    dumpManager: DumpManager,
     @Application applicationScope: CoroutineScope,
     private val keyguardInteractor: KeyguardInteractor,
-    keyguardTransitionInteractor: KeyguardTransitionInteractor,
+    private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
     private val shadeInteractor: ShadeInteractor,
     communalInteractor: CommunalInteractor,
     private val alternateBouncerToGoneTransitionViewModel:
@@ -115,7 +119,7 @@
     private val primaryBouncerToLockscreenTransitionViewModel:
         PrimaryBouncerToLockscreenTransitionViewModel,
     private val aodBurnInViewModel: AodBurnInViewModel,
-) {
+) : FlowDumperImpl(dumpManager) {
     private val statesForConstrainedNotifications: Set<KeyguardState> =
         setOf(AOD, LOCKSCREEN, DOZING, ALTERNATE_BOUNCER, PRIMARY_BOUNCER)
 
@@ -125,6 +129,7 @@
             .map { it.transitionState == STARTED || it.transitionState == RUNNING }
             .distinctUntilChanged()
             .onStart { emit(false) }
+            .dumpWhileCollecting("lockscreenToGlanceableHubRunning")
 
     private val glanceableHubToLockscreenRunning =
         keyguardTransitionInteractor
@@ -132,6 +137,7 @@
             .map { it.transitionState == STARTED || it.transitionState == RUNNING }
             .distinctUntilChanged()
             .onStart { emit(false) }
+            .dumpWhileCollecting("glanceableHubToLockscreenRunning")
 
     /**
      * Shade locked is a legacy concept, but necessary to mimic current functionality. Listen for
@@ -147,8 +153,10 @@
                 isShadeLocked && (isQsExpanded || isShadeExpanded)
             }
             .distinctUntilChanged()
+            .dumpWhileCollecting("isShadeLocked")
 
-    val shadeCollapseFadeInComplete = MutableStateFlow(false)
+    private val shadeCollapseFadeInComplete = MutableStateFlow(false)
+            .dumpValue("shadeCollapseFadeInComplete")
 
     val configurationBasedDimensions: Flow<ConfigurationBasedDimensions> =
         interactor.configurationBasedDimensions
@@ -170,6 +178,7 @@
                 )
             }
             .distinctUntilChanged()
+            .dumpWhileCollecting("configurationBasedDimensions")
 
     /** If the user is visually on one of the unoccluded lockscreen states. */
     val isOnLockscreen: Flow<Boolean> =
@@ -185,6 +194,7 @@
                 constrainedNotificationState || transitioningToOrFromLockscreen
             }
             .distinctUntilChanged()
+            .dumpWhileCollecting("isOnLockscreen")
 
     /** Are we purely on the keyguard without the shade/qs? */
     val isOnLockscreenWithoutShade: Flow<Boolean> =
@@ -203,6 +213,7 @@
                 started = SharingStarted.Eagerly,
                 initialValue = false,
             )
+            .dumpValue("isOnLockscreenWithoutShade")
 
     /** Are we purely on the glanceable hub without the shade/qs? */
     val isOnGlanceableHubWithoutShade: Flow<Boolean> =
@@ -221,20 +232,62 @@
                 started = SharingStarted.WhileSubscribed(),
                 initialValue = false,
             )
+            .dumpWhileCollecting("isOnGlanceableHubWithoutShade")
+
+    /**
+     * Fade in if the user swipes the shade back up, not if collapsed by going to AOD. This is
+     * needed due to the lack of a SHADE state with existing keyguard transitions.
+     */
+    private fun awaitCollapse(): Flow<Boolean> {
+        var aodTransitionIsComplete = true
+        return combine(
+                isOnLockscreenWithoutShade,
+                keyguardTransitionInteractor
+                    .isInTransitionWhere(
+                        fromStatePredicate = { it == LOCKSCREEN },
+                        toStatePredicate = { it == AOD }
+                    )
+                    .onStart { emit(false) },
+                ::Pair
+            )
+            .transformWhile { (isOnLockscreenWithoutShade, aodTransitionIsRunning) ->
+                // Wait until the AOD transition is complete before terminating
+                if (!aodTransitionIsComplete && !aodTransitionIsRunning) {
+                    aodTransitionIsComplete = true
+                    emit(false) // do not fade in
+                    false
+                } else if (aodTransitionIsRunning) {
+                    aodTransitionIsComplete = false
+                    true
+                } else if (isOnLockscreenWithoutShade) {
+                    // Shade is closed, fade in and terminate
+                    emit(true)
+                    false
+                } else {
+                    true
+                }
+            }
+    }
 
     /** Fade in only for use after the shade collapses */
     val shadeCollapseFadeIn: Flow<Boolean> =
         flow {
                 while (currentCoroutineContext().isActive) {
+                    // Ensure shade is collapsed
+                    isShadeLocked.first { !it }
                     emit(false)
                     // Wait for shade to be fully expanded
                     isShadeLocked.first { it }
-                    // ... and then for it to be collapsed
-                    isOnLockscreenWithoutShade.first { it }
-                    emit(true)
-                    // ... and then for the animation to complete
-                    shadeCollapseFadeInComplete.first { it }
-                    shadeCollapseFadeInComplete.value = false
+                    // ... and then for it to be collapsed OR a transition to AOD begins.
+                    // If AOD, do not fade in (a fade out occurs instead).
+                    awaitCollapse().collect { doFadeIn ->
+                        if (doFadeIn) {
+                            emit(true)
+                            // ... and then for the animation to complete
+                            shadeCollapseFadeInComplete.first { it }
+                            shadeCollapseFadeInComplete.value = false
+                        }
+                    }
                 }
             }
             .stateIn(
@@ -242,6 +295,7 @@
                 started = SharingStarted.WhileSubscribed(),
                 initialValue = false,
             )
+            .dumpWhileCollecting("shadeCollapseFadeIn")
 
     /**
      * The container occupies the entire screen, and must be positioned relative to other elements.
@@ -280,6 +334,7 @@
                 started = SharingStarted.Lazily,
                 initialValue = NotificationContainerBounds(),
             )
+            .dumpValue("bounds")
 
     /**
      * Ensure view is visible when the shade/qs are expanded. Also, as QS is expanding, fade out
@@ -303,6 +358,7 @@
                 }
             }
             .onStart { emit(0f) }
+            .dumpWhileCollecting("alphaForShadeAndQsExpansion")
 
     private val alphaWhenGoneAndShadeState: Flow<Float> =
         combineTransform(
@@ -315,6 +371,7 @@
                 emit(1f)
             }
         }
+        .dumpWhileCollecting("alphaWhenGoneAndShadeState")
 
     fun expansionAlpha(viewState: ViewStateAccessor): Flow<Float> {
         // All transition view models are mututally exclusive, and safe to merge
@@ -333,7 +390,7 @@
                 lockscreenToPrimaryBouncerTransitionViewModel.lockscreenAlpha,
                 occludedToAodTransitionViewModel.lockscreenAlpha,
                 occludedToLockscreenTransitionViewModel.lockscreenAlpha,
-                primaryBouncerToGoneTransitionViewModel.lockscreenAlpha,
+                primaryBouncerToGoneTransitionViewModel.notificationAlpha,
                 primaryBouncerToLockscreenTransitionViewModel.lockscreenAlpha,
             )
 
@@ -347,7 +404,9 @@
                     isOnLockscreenWithoutShade,
                     shadeCollapseFadeIn,
                     alphaForShadeAndQsExpansion,
-                    keyguardInteractor.dismissAlpha,
+                    keyguardInteractor.dismissAlpha.dumpWhileCollecting(
+                        "keyguardInteractor.keyguardAlpha"
+                    ),
                 ) {
                     isOnLockscreenWithoutShade,
                     shadeCollapseFadeIn,
@@ -363,6 +422,7 @@
                 },
             )
             .distinctUntilChanged()
+            .dumpWhileCollecting("expansionAlpha")
     }
 
     /**
@@ -396,6 +456,7 @@
                 }
             }
         }
+        .dumpWhileCollecting("glanceableHubAlpha")
 
     /**
      * Under certain scenarios, such as swiping up on the lockscreen, the container will need to be
@@ -416,6 +477,7 @@
                 0f
             }
         }
+        .dumpWhileCollecting("translationY")
     }
 
     /**
@@ -427,6 +489,7 @@
             lockscreenToGlanceableHubTransitionViewModel.notificationTranslationX,
             glanceableHubToLockscreenTransitionViewModel.notificationTranslationX,
         )
+        .dumpWhileCollecting("translationX")
 
     /**
      * When on keyguard, there is limited space to display notifications so calculate how many could
@@ -468,6 +531,7 @@
                 }
             }
             .distinctUntilChanged()
+            .dumpWhileCollecting("maxNotifications")
     }
 
     fun notificationStackChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
index 270b94b..23a080b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
@@ -45,8 +45,8 @@
 import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.shade.ShadeController
-import com.android.systemui.shade.ShadeViewController
 import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor
+import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.SysuiStatusBarStateController
@@ -71,7 +71,7 @@
     private val biometricUnlockControllerLazy: Lazy<BiometricUnlockController>,
     private val keyguardViewMediatorLazy: Lazy<KeyguardViewMediator>,
     private val shadeControllerLazy: Lazy<ShadeController>,
-    private val shadeViewControllerLazy: Lazy<ShadeViewController>,
+    private val commandQueue: CommandQueue,
     private val shadeAnimationInteractor: ShadeAnimationInteractor,
     private val statusBarKeyguardViewManagerLazy: Lazy<StatusBarKeyguardViewManager>,
     private val notifShadeWindowControllerLazy: Lazy<NotificationShadeWindowController>,
@@ -853,10 +853,11 @@
                 if (dismissShade) {
                     return StatusBarTransitionAnimatorController(
                         animationController,
-                        shadeViewControllerLazy.get(),
                         shadeAnimationInteractor,
                         shadeControllerLazy.get(),
                         notifShadeWindowControllerLazy.get(),
+                        commandQueue,
+                        displayId,
                         isLaunchForActivity
                     )
                 }
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 9052409..a1fae03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -39,11 +39,11 @@
 import com.android.keyguard.AuthKeyguardMessageArea;
 import com.android.systemui.Dumpable;
 import com.android.systemui.animation.ActivityTransitionAnimator;
+import com.android.systemui.animation.RemoteAnimationRunnerCompat;
 import com.android.systemui.display.data.repository.DisplayMetricsRepository;
 import com.android.systemui.navigationbar.NavigationBarView;
 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.notification.row.ExpandableNotificationRow;
 import com.android.systemui.util.Compile;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index 3669ba8..560d5ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -309,7 +309,7 @@
                 if (mVibrateOnOpening) {
                     vibrateOnNavigationKeyDown();
                 }
-                mShadeViewController.expand(true /* animate */);
+                mShadeController.animateExpandShade();
                 mNotificationStackScrollLayoutController.setWillExpand(true);
                 mHeadsUpManager.unpinAll(true /* userUnpinned */);
                 mMetricsLogger.count("panel_open", 1);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
index 6f992ac..d513f8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
@@ -15,10 +15,12 @@
 package com.android.systemui.statusbar.phone;
 
 import static com.android.systemui.plugins.DarkIconDispatcher.getTint;
+import static com.android.settingslib.flags.Flags.newStatusBarIcons;
 
 import android.animation.ArgbEvaluator;
 import android.content.Context;
 import android.content.res.ColorStateList;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.util.ArrayMap;
 import android.widget.ImageView;
@@ -66,10 +68,16 @@
             Context context,
             LightBarTransitionsController.Factory lightBarTransitionsControllerFactory,
             DumpManager dumpManager) {
-        mDarkModeIconColorSingleTone = context.getColor(
-                com.android.settingslib.R.color.dark_mode_icon_color_single_tone);
-        mLightModeIconColorSingleTone = context.getColor(
-                com.android.settingslib.R.color.light_mode_icon_color_single_tone);
+
+        if (newStatusBarIcons()) {
+            mDarkModeIconColorSingleTone = Color.BLACK;
+            mLightModeIconColorSingleTone = Color.WHITE;
+        } else {
+            mDarkModeIconColorSingleTone = context.getColor(
+                    com.android.settingslib.R.color.dark_mode_icon_color_single_tone);
+            mLightModeIconColorSingleTone = context.getColor(
+                    com.android.settingslib.R.color.light_mode_icon_color_single_tone);
+        }
 
         mTransitionsController = lightBarTransitionsControllerFactory.create(this);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index b07ba3c..a155e94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -67,7 +67,7 @@
     private static final String TAG = "HeadsUpManagerPhone";
 
     @VisibleForTesting
-    final int mExtensionTime;
+    public final int mExtensionTime;
     private final KeyguardBypassController mBypassController;
     private final GroupMembershipManager mGroupMembershipManager;
     private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 5a8b636..d975009 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -22,6 +22,7 @@
 import android.app.ActivityTaskManager;
 import android.app.AlarmManager;
 import android.app.AlarmManager.AlarmClockInfo;
+import android.app.NotificationManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -379,7 +380,7 @@
     }
 
     @Override
-    public void onConfigChanged(ZenModeConfig config) {
+    public void onConsolidatedPolicyChanged(NotificationManager.Policy policy) {
         updateVolumeZen();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index d10ca3d..6b47ac1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -239,10 +239,22 @@
         ViewGroup.LayoutParams layoutParams = getLayoutParams();
         mStatusBarHeight = SystemBarUtils.getStatusBarHeight(mContext);
         layoutParams.height = mStatusBarHeight - waterfallTopInset;
+        updateSystemIconsContainerHeight();
         updatePaddings();
         setLayoutParams(layoutParams);
     }
 
+    private void updateSystemIconsContainerHeight() {
+        View systemIconsContainer = findViewById(R.id.system_icons);
+        ViewGroup.LayoutParams layoutParams = systemIconsContainer.getLayoutParams();
+        int newSystemIconsHeight =
+                getResources().getDimensionPixelSize(R.dimen.status_bar_system_icons_height);
+        if (layoutParams.height != newSystemIconsHeight) {
+            layoutParams.height = newSystemIconsHeight;
+            systemIconsContainer.setLayoutParams(layoutParams);
+        }
+    }
+
     private void updatePaddings() {
         int statusBarPaddingStart = getResources().getDimensionPixelSize(
                 R.dimen.status_bar_padding_start);
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 a39bfe0..f29ec8f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -18,6 +18,7 @@
 import android.app.StatusBarManager.WINDOW_STATUS_BAR
 import android.graphics.Point
 import android.util.Log
+import android.view.InputDevice
 import android.view.MotionEvent
 import android.view.View
 import android.view.ViewGroup
@@ -81,7 +82,22 @@
         statusContainer.setOnHoverListener(
             statusOverlayHoverListenerFactory.createDarkAwareListener(statusContainer)
         )
-        statusContainer.setOnClickListener { shadeViewController.expand(/* animate= */true) }
+        statusContainer.setOnTouchListener(object : View.OnTouchListener {
+            override fun onTouch(v: View, event: MotionEvent): Boolean {
+                // We want to handle only mouse events here to avoid stealing finger touches from
+                // status bar which expands shade when swiped down on. We're using onTouchListener
+                // instead of onClickListener as the later will lead to isClickable being set to
+                // true and hence ALL touches always being intercepted. See [View.OnTouchEvent]
+                if (event.source == InputDevice.SOURCE_MOUSE) {
+                    if (event.action == MotionEvent.ACTION_UP) {
+                        v.performClick()
+                        shadeController.animateExpandShade()
+                    }
+                    return true
+                }
+                return false
+            }
+        })
 
         progressProvider?.setReadyToHandleTransition(true)
         configurationController.addCallback(configurationListener)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 29fd225..ee84434 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -23,7 +23,6 @@
 import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
-import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 import static com.android.systemui.util.kotlin.JavaAdapterKt.combineFlows;
 
 import android.content.Context;
@@ -82,6 +81,9 @@
 import com.android.systemui.navigationbar.TaskbarDelegate;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.scene.domain.interactor.SceneInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
+import com.android.systemui.scene.shared.model.Scenes;
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.shade.ShadeExpansionChangeEvent;
 import com.android.systemui.shade.ShadeExpansionListener;
@@ -98,6 +100,7 @@
 import com.android.systemui.unfold.FoldAodAnimationController;
 import com.android.systemui.unfold.SysUIUnfoldComponent;
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
+import com.android.systemui.util.kotlin.JavaAdapter;
 
 import dagger.Lazy;
 
@@ -157,6 +160,7 @@
     private final AlternateBouncerInteractor mAlternateBouncerInteractor;
     private final BouncerView mPrimaryBouncerView;
     private final Lazy<ShadeController> mShadeController;
+    private final Lazy<SceneInteractor> mSceneInteractorLazy;
 
     // Local cache of expansion events, to avoid duplicates
     private float mFraction = -1f;
@@ -348,6 +352,8 @@
     private Lazy<KeyguardSurfaceBehindInteractor> mSurfaceBehindInteractor;
     private Lazy<KeyguardDismissActionInteractor> mKeyguardDismissActionInteractor;
 
+    private final JavaAdapter mJavaAdapter;
+
     @Inject
     public StatusBarKeyguardViewManager(
             Context context,
@@ -378,7 +384,9 @@
             Lazy<WindowManagerLockscreenVisibilityInteractor> wmLockscreenVisibilityInteractor,
             Lazy<KeyguardDismissActionInteractor> keyguardDismissActionInteractorLazy,
             SelectedUserInteractor selectedUserInteractor,
-            Lazy<KeyguardSurfaceBehindInteractor> surfaceBehindInteractor
+            Lazy<KeyguardSurfaceBehindInteractor> surfaceBehindInteractor,
+            JavaAdapter javaAdapter,
+            Lazy<SceneInteractor> sceneInteractorLazy
     ) {
         mContext = context;
         mViewMediatorCallback = callback;
@@ -411,6 +419,8 @@
         mKeyguardDismissActionInteractor = keyguardDismissActionInteractorLazy;
         mSelectedUserInteractor = selectedUserInteractor;
         mSurfaceBehindInteractor = surfaceBehindInteractor;
+        mJavaAdapter = javaAdapter;
+        mSceneInteractorLazy = sceneInteractorLazy;
     }
 
     KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@@ -481,8 +491,7 @@
 
         if (KeyguardWmStateRefactor.isEnabled()) {
             // Show the keyguard views whenever we've told WM that the lockscreen is visible.
-            collectFlow(
-                    getViewRootImpl().getView(),
+            mJavaAdapter.alwaysCollectFlow(
                     combineFlows(
                             mWmLockscreenVisibilityInteractor.get().getLockscreenVisibility(),
                             mSurfaceBehindInteractor.get().isAnimatingSurface(),
@@ -630,8 +639,11 @@
     public void show(Bundle options) {
         Trace.beginSection("StatusBarKeyguardViewManager#show");
         mNotificationShadeWindowController.setKeyguardShowing(true);
-        mKeyguardStateController.notifyKeyguardState(true,
-                mKeyguardStateController.isOccluded());
+        if (SceneContainerFlag.isEnabled()) {
+            mSceneInteractorLazy.get().changeScene(
+                    Scenes.Lockscreen, "StatusBarKeyguardViewManager.show");
+        }
+        mKeyguardStateController.notifyKeyguardState(true, mKeyguardStateController.isOccluded());
         reset(true /* hideBouncerWhenShowing */);
         SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED,
                 SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN);
@@ -781,7 +793,7 @@
                     }
 
                     updateAlternateBouncerShowing(mAlternateBouncerInteractor.show());
-                    setKeyguardMessage(message, null);
+                    setKeyguardMessage(message, null, null);
                     return;
                 }
 
@@ -1444,11 +1456,12 @@
     }
 
     /** Display security message to relevant KeyguardMessageArea. */
-    public void setKeyguardMessage(String message, ColorStateList colorState) {
+    public void setKeyguardMessage(String message, ColorStateList colorState,
+            BiometricSourceType biometricSourceType) {
         if (mAlternateBouncerInteractor.isVisibleState()) {
             if (mKeyguardMessageAreaController != null) {
                 DeviceEntryUdfpsRefactor.assertInLegacyMode();
-                mKeyguardMessageAreaController.setMessage(message);
+                mKeyguardMessageAreaController.setMessage(message, biometricSourceType);
             }
         } else {
             mPrimaryBouncerInteractor.showMessage(message, colorState);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 5610ed9..b5ab4e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -63,6 +63,7 @@
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.shade.ShadeViewController;
 import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationClickNotifier;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationPresenter;
@@ -105,6 +106,7 @@
     private final NotificationVisibilityProvider mVisibilityProvider;
     private final HeadsUpManager mHeadsUpManager;
     private final ActivityStarter mActivityStarter;
+    private final CommandQueue mCommandQueue;
     private final NotificationClickNotifier mClickNotifier;
     private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     private final KeyguardManager mKeyguardManager;
@@ -143,6 +145,7 @@
             NotificationVisibilityProvider visibilityProvider,
             HeadsUpManager headsUpManager,
             ActivityStarter activityStarter,
+            CommandQueue commandQueue,
             NotificationClickNotifier clickNotifier,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
             KeyguardManager keyguardManager,
@@ -175,6 +178,7 @@
         mVisibilityProvider = visibilityProvider;
         mHeadsUpManager = headsUpManager;
         mActivityStarter = activityStarter;
+        mCommandQueue = commandQueue;
         mClickNotifier = clickNotifier;
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mKeyguardManager = keyguardManager;
@@ -444,10 +448,11 @@
             ActivityTransitionAnimator.Controller animationController =
                     new StatusBarTransitionAnimatorController(
                             mNotificationAnimationProvider.getAnimatorController(row, null),
-                            mShadeViewController,
                             mShadeAnimationInteractor,
                             mShadeController,
                             mNotificationShadeWindowController,
+                            mCommandQueue,
+                            mDisplayId,
                             isActivityIntent);
             mActivityTransitionAnimator.startPendingIntentWithAnimation(
                     animationController,
@@ -486,10 +491,11 @@
                     ActivityTransitionAnimator.Controller animationController =
                             new StatusBarTransitionAnimatorController(
                                     mNotificationAnimationProvider.getAnimatorController(row),
-                                    mShadeViewController,
                                     mShadeAnimationInteractor,
                                     mShadeController,
                                     mNotificationShadeWindowController,
+                                    mCommandQueue,
+                                    mDisplayId,
                                     true /* isActivityIntent */);
 
                     mActivityTransitionAnimator.startIntentWithAnimation(
@@ -537,10 +543,11 @@
                             viewController == null ? null
                                 : new StatusBarTransitionAnimatorController(
                                         viewController,
-                                        mShadeViewController,
                                         mShadeAnimationInteractor,
                                         mShadeController,
                                         mNotificationShadeWindowController,
+                                        mCommandQueue,
+                                        mDisplayId,
                                         true /* isActivityIntent */);
 
                     mActivityTransitionAnimator.startIntentWithAnimation(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTransitionAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTransitionAnimatorController.kt
index 7e907d8..705a11d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTransitionAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTransitionAnimatorController.kt
@@ -3,10 +3,13 @@
 import android.view.View
 import com.android.systemui.animation.ActivityTransitionAnimator
 import com.android.systemui.animation.TransitionAnimator
+import com.android.systemui.animation.TransitionAnimator.Companion.getProgress
+import com.android.systemui.dagger.qualifiers.DisplayId
 import com.android.systemui.shade.ShadeController
-import com.android.systemui.shade.ShadeViewController
 import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor
+import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment
 
 /**
  * A [ActivityTransitionAnimator.Controller] that takes care of collapsing the status bar at the
@@ -14,12 +17,15 @@
  */
 class StatusBarTransitionAnimatorController(
     private val delegate: ActivityTransitionAnimator.Controller,
-    private val shadeViewController: ShadeViewController,
     private val shadeAnimationInteractor: ShadeAnimationInteractor,
     private val shadeController: ShadeController,
     private val notificationShadeWindowController: NotificationShadeWindowController,
+    private val commandQueue: CommandQueue,
+    @DisplayId private val displayId: Int,
     private val isLaunchForActivity: Boolean = true
 ) : ActivityTransitionAnimator.Controller by delegate {
+    private var hideIconsDuringLaunchAnimation: Boolean = true
+
     // Always sync the opening window with the shade, given that we draw a hole punch in the shade
     // of the same size and position as the opening app to make it visible.
     override val openingWindowSyncView: View?
@@ -38,7 +44,7 @@
         delegate.onTransitionAnimationStart(isExpandingFullyAbove)
         shadeAnimationInteractor.setIsLaunchingActivity(true)
         if (!isExpandingFullyAbove) {
-            shadeViewController.collapseWithDuration(
+            shadeController.collapseWithDuration(
                 ActivityTransitionAnimator.TIMINGS.totalDuration.toInt()
             )
         }
@@ -56,7 +62,19 @@
         linearProgress: Float
     ) {
         delegate.onTransitionAnimationProgress(state, progress, linearProgress)
-        shadeViewController.applyLaunchAnimationProgress(linearProgress)
+        val hideIcons =
+            getProgress(
+                ActivityTransitionAnimator.TIMINGS,
+                linearProgress,
+                ANIMATION_DELAY_ICON_FADE_IN,
+                100
+            ) == 0.0f
+        if (hideIcons != hideIconsDuringLaunchAnimation) {
+            hideIconsDuringLaunchAnimation = hideIcons
+            if (!hideIcons) {
+                commandQueue.recomputeDisableFlags(displayId, true /* animate */)
+            }
+        }
     }
 
     override fun onTransitionAnimationCancelled(newKeyguardOccludedState: Boolean?) {
@@ -64,4 +82,12 @@
         shadeAnimationInteractor.setIsLaunchingActivity(false)
         shadeController.onLaunchAnimationCancelled(isLaunchForActivity)
     }
+
+    companion object {
+        val ANIMATION_DELAY_ICON_FADE_IN =
+            (ActivityTransitionAnimator.TIMINGS.totalDuration -
+                CollapsedStatusBarFragment.FADE_IN_DURATION -
+                CollapsedStatusBarFragment.FADE_IN_DELAY -
+                48)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
index a608be3..8f3b0e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.pipeline.mobile.data.repository
 
+import android.telephony.CellSignalStrength
 import android.telephony.SubscriptionInfo
 import android.telephony.TelephonyManager
 import com.android.systemui.log.table.TableLogBuffer
@@ -149,6 +150,6 @@
 
     companion object {
         /** The default number of levels to use for [numberOfLevels]. */
-        const val DEFAULT_NUM_LEVELS = 4
+        val DEFAULT_NUM_LEVELS = CellSignalStrength.getNumSignalStrengthLevels()
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
index 6de7a00..3cb138bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
@@ -25,6 +25,7 @@
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_CARRIER_ID
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_CARRIER_NETWORK_CHANGE
@@ -223,6 +224,9 @@
 
         _carrierId.value = event.carrierId ?: INVALID_SUBSCRIPTION_ID
 
+        numberOfLevels.value =
+            if (event.inflateStrength) DEFAULT_NUM_LEVELS + 1 else DEFAULT_NUM_LEVELS
+
         cdmaRoaming.value = event.roaming
         _isRoaming.value = event.roaming
         // TODO(b/261029387): not yet supported
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoModeMobileConnectionDataSource.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoModeMobileConnectionDataSource.kt
index 11a61a9..dbfc576 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoModeMobileConnectionDataSource.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoModeMobileConnectionDataSource.kt
@@ -71,7 +71,7 @@
         val dataType = getString("datatype")?.toDataType()
         val slot = getString("slot")?.toInt()
         val carrierId = getString("carrierid")?.toInt()
-        val inflateStrength = getString("inflate")?.toBoolean()
+        val inflateStrength = getString("inflate").toBoolean()
         val activity = getString("activity")?.toActivity()
         val carrierNetworkChange = getString("carriernetworkchange") == "show"
         val roaming = getString("roam") == "show"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/model/FakeNetworkEventModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/model/FakeNetworkEventModel.kt
index 4836abe..42171d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/model/FakeNetworkEventModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/model/FakeNetworkEventModel.kt
@@ -31,7 +31,7 @@
         // Null means the default (chosen by the repository)
         val subId: Int?,
         val carrierId: Int?,
-        val inflateStrength: Boolean?,
+        val inflateStrength: Boolean = false,
         @DataActivityType val activity: Int?,
         val carrierNetworkChange: Boolean,
         val roaming: Boolean,
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 6b30326..adcf736 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
@@ -69,6 +69,9 @@
     /** True if we consider this connection to be in service, i.e. can make calls */
     val isInService: StateFlow<Boolean>
 
+    /** True if this connection is emergency only */
+    val isEmergencyOnly: StateFlow<Boolean>
+
     /** Observable for the data enabled state of this connection */
     val isDataEnabled: StateFlow<Boolean>
 
@@ -292,12 +295,7 @@
             }
             .stateIn(scope, SharingStarted.WhileSubscribed(), 0)
 
-    private val numberOfLevels: StateFlow<Int> =
-        connectionRepository.numberOfLevels.stateIn(
-            scope,
-            SharingStarted.WhileSubscribed(),
-            connectionRepository.numberOfLevels.value,
-        )
+    private val numberOfLevels: StateFlow<Int> = connectionRepository.numberOfLevels
 
     override val isDataConnected: StateFlow<Boolean> =
         connectionRepository.dataConnectionState
@@ -306,6 +304,8 @@
 
     override val isInService = connectionRepository.isInService
 
+    override val isEmergencyOnly: StateFlow<Boolean> = connectionRepository.isEmergencyOnly
+
     override val isAllowedDuringAirplaneMode = connectionRepository.isAllowedDuringAirplaneMode
 
     /** Whether or not to show the error state of [SignalDrawable] */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
index 900a920..fd5ab13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
@@ -19,6 +19,8 @@
 import android.content.Context
 import android.util.AttributeSet
 import android.view.LayoutInflater
+import android.widget.ImageView
+import com.android.settingslib.flags.Flags.newStatusBarIcons
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.StatusBarIconView.getVisibleStateString
 import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
@@ -59,6 +61,18 @@
                     .inflate(R.layout.status_bar_mobile_signal_group_new, null)
                     as ModernStatusBarMobileView)
                 .also {
+                    // Flag-specific configuration
+                    if (newStatusBarIcons()) {
+                        // New icon (with no embedded whitespace) is slightly shorter
+                        // (but actually taller)
+                        val iconView = it.requireViewById<ImageView>(R.id.mobile_signal)
+                        val lp = iconView.layoutParams
+                        lp.height =
+                            context.resources.getDimensionPixelSize(
+                                R.dimen.status_bar_mobile_signal_size_updated
+                            )
+                    }
+
                     it.subId = viewModel.subscriptionId
                     it.initView(slot) {
                         MobileIconBinder.bind(view = it, viewModel = viewModel, logger = logger)
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 be843ba..deae576 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
@@ -22,7 +22,6 @@
 import com.android.systemui.flags.FeatureFlagsClassic
 import com.android.systemui.statusbar.phone.StatusBarLocation
 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.MobileViewLogger
 import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
@@ -31,6 +30,8 @@
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancel
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.flatMapLatest
@@ -58,9 +59,8 @@
     private val flags: FeatureFlagsClassic,
     @Application private val scope: CoroutineScope,
 ) {
-    @VisibleForTesting val mobileIconSubIdCache = mutableMapOf<Int, MobileIconViewModel>()
     @VisibleForTesting
-    val mobileIconInteractorSubIdCache = mutableMapOf<Int, MobileIconInteractor>()
+    val reuseCache = mutableMapOf<Int, Pair<MobileIconViewModel, CoroutineScope>>()
 
     val subscriptionIdsFlow: StateFlow<List<Int>> =
         interactor.filteredSubscriptions
@@ -109,24 +109,37 @@
     }
 
     private fun commonViewModelForSub(subId: Int): MobileIconViewModelCommon {
-        return mobileIconSubIdCache[subId]
-            ?: MobileIconViewModel(
-                    subId,
-                    interactor.getMobileConnectionInteractorForSubId(subId),
-                    airplaneModeInteractor,
-                    constants,
-                    flags,
-                    scope,
-                )
-                .also { mobileIconSubIdCache[subId] = it }
+        return reuseCache.getOrPut(subId) { createViewModel(subId) }.first
     }
 
-    private fun invalidateCaches(subIds: List<Int>) {
-        val subIdsToRemove = mobileIconSubIdCache.keys.filter { !subIds.contains(it) }
-        subIdsToRemove.forEach { mobileIconSubIdCache.remove(it) }
+    private fun createViewModel(subId: Int): Pair<MobileIconViewModel, CoroutineScope> {
+        // Create a child scope so we can cancel it
+        val vmScope = scope.createChildScope()
+        val vm =
+            MobileIconViewModel(
+                subId,
+                interactor.getMobileConnectionInteractorForSubId(subId),
+                airplaneModeInteractor,
+                constants,
+                flags,
+                vmScope,
+            )
 
-        mobileIconInteractorSubIdCache.keys
+        return Pair(vm, vmScope)
+    }
+
+    private fun CoroutineScope.createChildScope() =
+        CoroutineScope(coroutineContext + Job(coroutineContext[Job]))
+
+    private fun invalidateCaches(subIds: List<Int>) {
+        reuseCache.keys
             .filter { !subIds.contains(it) }
-            .forEach { subId -> mobileIconInteractorSubIdCache.remove(subId) }
+            .forEach { id ->
+                reuseCache
+                    .remove(id)
+                    // Cancel the view model's scope after removing it
+                    ?.second
+                    ?.cancel()
+            }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
index 6e1114c..3f89d04b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
@@ -72,9 +72,16 @@
     /** When all connections are considered OOS, satellite connectivity is potentially valid */
     val areAllConnectionsOutOfService =
         if (Flags.oemEnabledSatelliteFlag()) {
-                iconsInteractor.icons.aggregateOver(selector = { intr -> intr.isInService }) {
-                    isInServiceList ->
-                    isInServiceList.all { !it }
+                iconsInteractor.icons.aggregateOver(
+                    selector = { intr ->
+                        combine(intr.isInService, intr.isEmergencyOnly) {
+                            isInService,
+                            isEmergencyOnly ->
+                            !isInService && !isEmergencyOnly
+                        }
+                    }
+                ) { isOosAndIsNotEmergencyOnly ->
+                    isOosAndIsNotEmergencyOnly.all { it }
                 }
             } else {
                 flowOf(false)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt
index 4cd3484..ba55aad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt
@@ -20,6 +20,9 @@
 import android.content.Context
 import android.util.AttributeSet
 import android.view.LayoutInflater
+import android.view.ViewGroup
+import android.widget.ImageView
+import com.android.settingslib.flags.Flags.newStatusBarIcons
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.StatusBarIconView
 import com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarView
@@ -57,7 +60,18 @@
         ): ModernStatusBarWifiView {
             return (LayoutInflater.from(context).inflate(R.layout.new_status_bar_wifi_group, null)
                     as ModernStatusBarWifiView)
-                .also { it.initView(slot) { WifiViewBinder.bind(it, wifiViewModel) } }
+                .also {
+                    // Flag-specific configuration
+                    if (newStatusBarIcons()) {
+                        // The newer asset does not embed whitespace around it, and is therefore
+                        // rectangular. Use wrap_content for the width in this case
+                        val iconView = it.requireViewById<ImageView>(R.id.wifi_signal)
+                        val lp = iconView.layoutParams
+                        lp.width = ViewGroup.LayoutParams.WRAP_CONTENT
+                    }
+
+                    it.initView(slot) { WifiViewBinder.bind(it, wifiViewModel) }
+                }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
index 2c1780d..530e49c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
@@ -304,14 +304,15 @@
         if (!isPinned) {
             headsUpEntry.mWasUnpinned = true;
         }
-        if (entry.isRowPinned() != isPinned) {
-            entry.setRowPinned(isPinned);
+        if (headsUpEntry.isPinned() != isPinned) {
+            headsUpEntry.setPinned(isPinned);
             updatePinnedMode();
             if (isPinned && entry.getSbn() != null) {
-                mUiEventLogger.logWithInstanceId(
+               mUiEventLogger.logWithInstanceId(
                         NotificationPeekEvent.NOTIFICATION_PEEK, entry.getSbn().getUid(),
                         entry.getSbn().getPackageName(), entry.getSbn().getInstanceId());
             }
+            // TODO(b/325936094) convert these listeners to collecting a flow
             for (OnHeadsUpChangedListener listener : mListeners) {
                 if (isPinned) {
                     listener.onHeadsUpPinned(entry);
@@ -662,6 +663,14 @@
             updateEntry(true /* updatePostTime */, "setEntry");
         }
 
+        public boolean isPinned() {
+            return mEntry != null && mEntry.isRowPinned();
+        }
+
+        public void setPinned(boolean pinned) {
+            if (mEntry != null) mEntry.setRowPinned(pinned);
+        }
+
         /**
          * Updates an entry's removal time.
          * @param updatePostTime whether or not to refresh the post time
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/BatteryControllerExt.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/BatteryControllerExt.kt
new file mode 100644
index 0000000..0128eb7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/BatteryControllerExt.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.kotlin
+
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.statusbar.policy.BatteryController
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.onStart
+
+fun BatteryController.isBatteryPowerSaveEnabled(): Flow<Boolean> {
+    return conflatedCallbackFlow {
+            val batteryCallback =
+                object : BatteryController.BatteryStateChangeCallback {
+                    override fun onPowerSaveChanged(isPowerSave: Boolean) {
+                        trySend(isPowerSave)
+                    }
+                }
+            addCallback(batteryCallback)
+            awaitClose { removeCallback(batteryCallback) }
+        }
+        .onStart { emit(isPowerSave) }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/RotationLockControllerExt.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/RotationLockControllerExt.kt
new file mode 100644
index 0000000..22cc8dd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/RotationLockControllerExt.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.kotlin
+
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.statusbar.policy.RotationLockController
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.onStart
+
+fun RotationLockController.isRotationLockEnabled(): Flow<Boolean> {
+    return conflatedCallbackFlow {
+            val rotationLockCallback =
+                RotationLockController.RotationLockControllerCallback { rotationLocked, _ ->
+                    trySend(rotationLocked)
+                }
+            addCallback(rotationLockCallback)
+            awaitClose { removeCallback(rotationLockCallback) }
+        }
+        .onStart { emit(isRotationLocked) }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java b/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
index 3d724e1..0dcbe9b2 100644
--- a/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
+++ b/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
@@ -158,11 +158,11 @@
         try {
             bindResult = mContext.bindServiceAsUser(mServiceIntent, this, mFlags,
                     mUserTracker.getUserHandle());
+            mBoundCalled = true;
         } catch (SecurityException e) {
             Log.d(TAG, "Could not bind to service", e);
             mContext.unbindService(this);
         }
-        mBoundCalled = true;
         if (DEBUG) {
             Log.d(TAG, "bind. bound:" + bindResult);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/ClientTrackingWakeLock.kt b/packages/SystemUI/src/com/android/systemui/util/wakelock/ClientTrackingWakeLock.kt
new file mode 100644
index 0000000..db300eb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/ClientTrackingWakeLock.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.wakelock
+
+import android.os.PowerManager
+import android.util.Log
+import java.util.concurrent.ConcurrentHashMap
+import java.util.concurrent.atomic.AtomicInteger
+
+/**
+ * [PowerManager.WakeLock] wrapper that tracks acquire/release reasons and logs them if owning
+ * logger is enabled.
+ */
+class ClientTrackingWakeLock(
+    private val pmWakeLock: PowerManager.WakeLock,
+    private val logger: WakeLockLogger?,
+    private val maxTimeout: Long
+) : WakeLock {
+
+    private val activeClients = ConcurrentHashMap<String, AtomicInteger>()
+
+    override fun acquire(why: String) {
+        val count = activeClients.computeIfAbsent(why) { _ -> AtomicInteger(0) }.incrementAndGet()
+        logger?.logAcquire(pmWakeLock, why, count)
+        pmWakeLock.acquire(maxTimeout)
+    }
+
+    override fun release(why: String) {
+        val count = activeClients[why]?.decrementAndGet() ?: -1
+        if (count < 0) {
+            Log.wtf(WakeLock.TAG, "Releasing WakeLock with invalid reason: $why")
+            // Restore count just in case.
+            activeClients[why]?.incrementAndGet()
+            return
+        }
+
+        logger?.logRelease(pmWakeLock, why, count)
+        pmWakeLock.release()
+    }
+
+    override fun wrap(r: Runnable): Runnable = WakeLock.wrapImpl(this, r)
+
+    fun activeClients(): Int =
+        activeClients.reduceValuesToInt(Long.MAX_VALUE, AtomicInteger::get, 0, Integer::sum)
+
+    override fun toString(): String {
+        return "active clients=${activeClients()}"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
index 039109e..d2ed71c 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
@@ -19,8 +19,11 @@
 import android.content.Context;
 import android.os.Handler;
 
+import com.android.systemui.Flags;
 import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 
+import dagger.Lazy;
 import dagger.assisted.Assisted;
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
@@ -37,10 +40,13 @@
     private final WakeLock mInner;
 
     @AssistedInject
-    public DelayedWakeLock(@Background Handler handler, Context context, WakeLockLogger logger,
+    public DelayedWakeLock(@Background Lazy<Handler> bgHandler,
+                           @Main Lazy<Handler> mainHandler,
+                           Context context, WakeLockLogger logger,
             @Assisted String tag) {
         mInner = WakeLock.createPartial(context, logger, tag);
-        mHandler = handler;
+        mHandler = Flags.delayedWakelockReleaseOnBackgroundThread() ? bgHandler.get()
+                : mainHandler.get();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
index 6128fee..707751a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
@@ -22,6 +22,8 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.systemui.Flags;
+
 import java.util.HashMap;
 
 import javax.inject.Inject;
@@ -112,6 +114,11 @@
     @VisibleForTesting
     static WakeLock wrap(
             final PowerManager.WakeLock inner, WakeLockLogger logger, long maxTimeout) {
+        if (Flags.delayedWakelockReleaseOnBackgroundThread()) {
+            return new ClientTrackingWakeLock(inner, logger, maxTimeout);
+        }
+
+        // Non-thread safe implementation, remove when flag above is removed.
         return new WakeLock() {
             private final HashMap<String, Integer> mActiveClients = new HashMap<>();
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/SpatializerModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/SpatializerModule.kt
index 18a9161..593b90a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/SpatializerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/SpatializerModule.kt
@@ -21,15 +21,19 @@
 import com.android.settingslib.media.data.repository.SpatializerRepository
 import com.android.settingslib.media.data.repository.SpatializerRepositoryImpl
 import com.android.settingslib.media.domain.interactor.SpatializerInteractor
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import dagger.Module
 import dagger.Provides
 import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
 
 /** Spatializer module. */
 @Module
 interface SpatializerModule {
+
     companion object {
+
         @Provides
         fun provideSpatializer(
             audioManager: AudioManager,
@@ -38,8 +42,9 @@
         @Provides
         fun provdieSpatializerRepository(
             spatializer: Spatializer,
+            @Application scope: CoroutineScope,
             @Background backgroundContext: CoroutineContext,
-        ): SpatializerRepository = SpatializerRepositoryImpl(spatializer, backgroundContext)
+        ): SpatializerRepository = SpatializerRepositoryImpl(spatializer, scope, backgroundContext)
 
         @Provides
         fun provideSpatializerInetractor(repository: SpatializerRepository): SpatializerInteractor =
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteria.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteria.kt
new file mode 100644
index 0000000..71bce5e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteria.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.spatial.domain
+
+import com.android.systemui.volume.panel.component.spatial.domain.interactor.SpatialAudioComponentInteractor
+import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioAvailabilityModel
+import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
+import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+@VolumePanelScope
+class SpatialAudioAvailabilityCriteria
+@Inject
+constructor(private val interactor: SpatialAudioComponentInteractor) :
+    ComponentAvailabilityCriteria {
+
+    override fun isAvailable(): Flow<Boolean> =
+        interactor.isAvailable.map { it is SpatialAudioAvailabilityModel.SpatialAudio }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt
new file mode 100644
index 0000000..4358611
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.spatial.domain.interactor
+
+import android.media.AudioDeviceAttributes
+import android.media.AudioDeviceInfo
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.media.BluetoothMediaDevice
+import com.android.settingslib.media.domain.interactor.SpatializerInteractor
+import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
+import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioAvailabilityModel
+import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioEnabledModel
+import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * Provides an ability to access and update spatial audio and head tracking state.
+ *
+ * Head tracking is a sub-feature of spatial audio. This means that it requires spatial audio to be
+ * available for it to be available. And spatial audio to be enabled for it to be enabled.
+ */
+@VolumePanelScope
+class SpatialAudioComponentInteractor
+@Inject
+constructor(
+    mediaOutputInteractor: MediaOutputInteractor,
+    private val spatializerInteractor: SpatializerInteractor,
+    @VolumePanelScope private val coroutineScope: CoroutineScope,
+) {
+
+    private val changes = MutableSharedFlow<Unit>()
+    private val currentAudioDeviceAttributes: StateFlow<AudioDeviceAttributes?> =
+        mediaOutputInteractor.currentConnectedDevice
+            .map { mediaDevice ->
+                mediaDevice ?: return@map null
+                val btDevice: CachedBluetoothDevice =
+                    (mediaDevice as? BluetoothMediaDevice)?.cachedDevice ?: return@map null
+                btDevice.getAudioDeviceAttributes()
+            }
+            .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), null)
+
+    /**
+     * Returns spatial audio availability model. It can be:
+     * - unavailable
+     * - only spatial audio is available
+     * - spatial audio and head tracking are available
+     */
+    val isAvailable: StateFlow<SpatialAudioAvailabilityModel> =
+        combine(
+                currentAudioDeviceAttributes,
+                changes.onStart { emit(Unit) },
+                spatializerInteractor.isHeadTrackingAvailable,
+            ) { attributes, _, isHeadTrackingAvailable ->
+                attributes ?: return@combine SpatialAudioAvailabilityModel.Unavailable
+                if (isHeadTrackingAvailable) {
+                    return@combine SpatialAudioAvailabilityModel.HeadTracking
+                }
+                if (spatializerInteractor.isSpatialAudioAvailable(attributes)) {
+                    return@combine SpatialAudioAvailabilityModel.SpatialAudio
+                }
+                SpatialAudioAvailabilityModel.Unavailable
+            }
+            .stateIn(
+                coroutineScope,
+                SharingStarted.Eagerly,
+                SpatialAudioAvailabilityModel.Unavailable,
+            )
+
+    /**
+     * Returns spatial audio enabled/disabled model. It can be
+     * - disabled
+     * - only spatial audio is enabled
+     * - spatial audio and head tracking are enabled
+     */
+    val isEnabled: StateFlow<SpatialAudioEnabledModel> =
+        combine(
+                changes.onStart { emit(Unit) },
+                currentAudioDeviceAttributes,
+                isAvailable,
+            ) { _, attributes, isAvailable ->
+                if (isAvailable is SpatialAudioAvailabilityModel.Unavailable) {
+                    return@combine SpatialAudioEnabledModel.Disabled
+                }
+                attributes ?: return@combine SpatialAudioEnabledModel.Disabled
+                if (spatializerInteractor.isHeadTrackingEnabled(attributes)) {
+                    return@combine SpatialAudioEnabledModel.HeadTrackingEnabled
+                }
+                if (spatializerInteractor.isSpatialAudioEnabled(attributes)) {
+                    return@combine SpatialAudioEnabledModel.SpatialAudioEnabled
+                }
+                SpatialAudioEnabledModel.Disabled
+            }
+            .stateIn(
+                coroutineScope,
+                SharingStarted.Eagerly,
+                SpatialAudioEnabledModel.Disabled,
+            )
+
+    /**
+     * Sets current [isEnabled] to a specific [SpatialAudioEnabledModel]. It
+     * - disables both spatial audio and head tracking
+     * - enables only spatial audio
+     * - enables both spatial audio and head tracking
+     */
+    suspend fun setEnabled(model: SpatialAudioEnabledModel) {
+        val attributes = currentAudioDeviceAttributes.value ?: return
+        spatializerInteractor.setSpatialAudioEnabled(
+            attributes,
+            model is SpatialAudioEnabledModel.SpatialAudioEnabled,
+        )
+        spatializerInteractor.setHeadTrackingEnabled(
+            attributes,
+            model is SpatialAudioEnabledModel.HeadTrackingEnabled,
+        )
+        changes.emit(Unit)
+    }
+
+    private suspend fun CachedBluetoothDevice.getAudioDeviceAttributes(): AudioDeviceAttributes? {
+        return listOf(
+                AudioDeviceAttributes(
+                    AudioDeviceAttributes.ROLE_OUTPUT,
+                    AudioDeviceInfo.TYPE_BLE_HEADSET,
+                    address
+                ),
+                AudioDeviceAttributes(
+                    AudioDeviceAttributes.ROLE_OUTPUT,
+                    AudioDeviceInfo.TYPE_BLE_SPEAKER,
+                    address
+                ),
+                AudioDeviceAttributes(
+                    AudioDeviceAttributes.ROLE_OUTPUT,
+                    AudioDeviceInfo.TYPE_BLE_BROADCAST,
+                    address
+                ),
+                AudioDeviceAttributes(
+                    AudioDeviceAttributes.ROLE_OUTPUT,
+                    AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
+                    address
+                ),
+                AudioDeviceAttributes(
+                    AudioDeviceAttributes.ROLE_OUTPUT,
+                    AudioDeviceInfo.TYPE_HEARING_AID,
+                    address
+                )
+            )
+            .firstOrNull { spatializerInteractor.isSpatialAudioAvailable(it) }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioAvailabilityModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioAvailabilityModel.kt
new file mode 100644
index 0000000..cf14546
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioAvailabilityModel.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.spatial.domain.model
+
+/** Models spatial audio and head tracking availability. */
+interface SpatialAudioAvailabilityModel {
+
+    /** Spatial audio is unavailable. */
+    data object Unavailable : SpatialAudioAvailabilityModel
+
+    /** Spatial audio is available. */
+    interface SpatialAudio : SpatialAudioAvailabilityModel {
+        companion object : SpatialAudio
+    }
+
+    /** Head tracking is available. This also means that [SpatialAudio] is available. */
+    data object HeadTracking : SpatialAudio
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioEnabledModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioEnabledModel.kt
new file mode 100644
index 0000000..4e65f60
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioEnabledModel.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.spatial.domain.model
+
+/** Models spatial audio and head tracking enabled/disabled state. */
+interface SpatialAudioEnabledModel {
+
+    /** Spatial audio is disabled. */
+    data object Disabled : SpatialAudioEnabledModel
+
+    /** Spatial audio is enabled. */
+    interface SpatialAudioEnabled : SpatialAudioEnabledModel {
+        companion object : SpatialAudioEnabled
+    }
+
+    /** Head tracking is enabled. This also means that [SpatialAudioEnabled]. */
+    data object HeadTrackingEnabled : SpatialAudioEnabled
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/shared/flag/VolumePanelFlag.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/shared/flag/VolumePanelFlag.kt
index d90a9c7..485f4b5 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/shared/flag/VolumePanelFlag.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/shared/flag/VolumePanelFlag.kt
@@ -17,23 +17,18 @@
 package com.android.systemui.volume.panel.shared.flag
 
 import com.android.systemui.Flags
-import com.android.systemui.compose.ComposeFacade
 import com.android.systemui.flags.RefactorFlagUtils
 import javax.inject.Inject
 
 /** Provides a flag to check for the new Compose based Volume Panel availability. */
 class VolumePanelFlag @Inject constructor() {
 
-    /**
-     * Returns true when the new Volume Panel is available and false the otherwise. The new panel
-     * can only be available when [ComposeFacade.isComposeAvailable] is true.
-     */
+    /** Returns true when the new Volume Panel is available and false the otherwise. */
     fun canUseNewVolumePanel(): Boolean {
-        return ComposeFacade.isComposeAvailable() && Flags.newVolumePanel()
+        return Flags.newVolumePanel()
     }
 
     fun assertNewVolumePanel() {
-        require(ComposeFacade.isComposeAvailable())
         RefactorFlagUtils.assertInNewMode(Flags.newVolumePanel(), Flags.FLAG_NEW_VOLUME_PANEL)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/activity/VolumePanelActivity.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/activity/VolumePanelActivity.kt
index 53e1b8b..d430e65 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/activity/VolumePanelActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/activity/VolumePanelActivity.kt
@@ -18,11 +18,12 @@
 
 import android.os.Bundle
 import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
 import androidx.activity.enableEdgeToEdge
 import androidx.activity.viewModels
-import com.android.systemui.compose.ComposeFacade
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.volume.panel.shared.flag.VolumePanelFlag
+import com.android.systemui.volume.panel.ui.composable.VolumePanelRoot
 import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel
 import javax.inject.Inject
 import javax.inject.Provider
@@ -44,7 +45,7 @@
 
         volumePanelFlag.assertNewVolumePanel()
 
-        ComposeFacade.setVolumePanelActivityContent(this, viewModel) { finish() }
+        setContent { VolumePanelRoot(viewModel = viewModel, onDismiss = ::finish) }
     }
 
     override fun onContentChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
index f498520..1a39934 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
@@ -20,6 +20,7 @@
 import static com.android.systemui.wallet.ui.WalletCardCarousel.CARD_ANIM_ALPHA_DURATION;
 
 import android.annotation.Nullable;
+import android.app.ActivityOptions;
 import android.app.BroadcastOptions;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -40,8 +41,8 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.Utils;
-import com.android.systemui.res.R;
 import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.res.R;
 
 import java.util.List;
 
@@ -308,7 +309,7 @@
                             BroadcastOptions options = BroadcastOptions.makeBasic();
                             options.setInteractive(true);
                             options.setPendingIntentBackgroundActivityStartMode(
-                                    BroadcastOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+                                    ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
                             walletCard.getPendingIntent().send(options.toBundle());
                         } catch (PendingIntent.CanceledException e) {
                             Log.w(TAG, "Error sending pending intent for wallet card.");
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 65dede8..cb61534 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -28,6 +28,7 @@
 import static com.android.server.notification.Flags.screenshareNotificationHiding;
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
 
 import android.app.INotificationManager;
 import android.app.Notification;
@@ -50,6 +51,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.flags.FeatureFlags;
@@ -97,6 +99,7 @@
     private final Context mContext;
     private final Bubbles mBubbles;
     private final NotificationShadeWindowController mNotificationShadeWindowController;
+    private final KeyguardStateController mKeyguardStateController;
     private final ShadeController mShadeController;
     private final IStatusBarService mBarService;
     private final INotificationManager mNotificationManager;
@@ -109,6 +112,7 @@
     private final NotifPipeline mNotifPipeline;
     private final NotifPipelineFlags mNotifPipelineFlags;
     private final Executor mSysuiMainExecutor;
+    private final Executor mSysuiUiBgExecutor;
 
     private final Bubbles.SysuiProxy mSysuiProxy;
     // TODO (b/145659174): allow for multiple callbacks to support the "shadow" new notif pipeline
@@ -116,6 +120,8 @@
     private final StatusBarWindowCallback mStatusBarWindowCallback;
     private final Runnable mSensitiveStateChangedListener;
     private boolean mPanelExpanded;
+    private boolean mKeyguardShowing;
+    private boolean mDreamingOrInPreview;
 
     /**
      * Creates {@link BubblesManager}, returns {@code null} if Optional {@link Bubbles} not present
@@ -140,7 +146,8 @@
             SysUiState sysUiState,
             FeatureFlags featureFlags,
             NotifPipelineFlags notifPipelineFlags,
-            Executor sysuiMainExecutor) {
+            Executor sysuiMainExecutor,
+            Executor sysuiUiBgExecutor) {
         if (bubblesOptional.isPresent()) {
             return new BubblesManager(context,
                     bubblesOptional.get(),
@@ -160,7 +167,8 @@
                     sysUiState,
                     featureFlags,
                     notifPipelineFlags,
-                    sysuiMainExecutor);
+                    sysuiMainExecutor,
+                    sysuiUiBgExecutor);
         } else {
             return null;
         }
@@ -185,10 +193,12 @@
             SysUiState sysUiState,
             FeatureFlags featureFlags,
             NotifPipelineFlags notifPipelineFlags,
-            Executor sysuiMainExecutor) {
+            Executor sysuiMainExecutor,
+            Executor sysuiUiBgExecutor) {
         mContext = context;
         mBubbles = bubbles;
         mNotificationShadeWindowController = notificationShadeWindowController;
+        mKeyguardStateController = keyguardStateController;
         mShadeController = shadeController;
         mNotificationManager = notificationManager;
         mDreamManager = dreamManager;
@@ -200,6 +210,7 @@
         mNotifPipeline = notifPipeline;
         mNotifPipelineFlags = notifPipelineFlags;
         mSysuiMainExecutor = sysuiMainExecutor;
+        mSysuiUiBgExecutor = sysuiUiBgExecutor;
 
         mBarService = statusBarService == null
                 ? IStatusBarService.Stub.asInterface(
@@ -208,12 +219,11 @@
 
         setupNotifPipeline();
 
-        keyguardStateController.addCallback(new KeyguardStateController.Callback() {
+        // TODO(b/327410864): use KeyguardTransitionInteractor to listen for keyguard changes
+        mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
             @Override
             public void onKeyguardShowingChanged() {
-                boolean isUnlockedShade = !keyguardStateController.isShowing()
-                        && !isDreamingOrInPreview();
-                bubbles.onStatusBarStateChanged(isUnlockedShade);
+                updateKeyguardAndDreamingState();
             }
         });
 
@@ -256,6 +266,14 @@
                         mPanelExpanded = panelExpanded;
                         mBubbles.onNotificationPanelExpandedChanged(panelExpanded);
                     }
+                    if (!mKeyguardShowing && mDreamingOrInPreview && !isDreaming) {
+                        // We check for dreaming state changes when keyguard status changes.
+                        // This causes us to miss events if dreaming state changes after keyguard.
+                        // Add a check here for the case where keyguard is dismissed before
+                        // dreaming state changes. Otherwise bubbles remain invisible.
+                        // TODO(b/327410864): use KeyguardTransitionInteractor for dreaming changes
+                        updateKeyguardAndDreamingState();
+                    }
                 };
         notificationShadeWindowController.registerCallback(mStatusBarWindowCallback);
 
@@ -395,6 +413,19 @@
         mBubbles.setSysuiProxy(mSysuiProxy);
     }
 
+    private void updateKeyguardAndDreamingState() {
+        mSysuiUiBgExecutor.execute(() -> {
+            mKeyguardShowing = mKeyguardStateController.isShowing();
+            mDreamingOrInPreview = isDreamingOrInPreview();
+            boolean isUnlockedShade = !mKeyguardShowing && !mDreamingOrInPreview;
+            ProtoLog.d(WM_SHELL_BUBBLES,
+                    "handleKeyguardOrDreamChange isUnlockedShade=%b keyguardShowing=%b "
+                            + "dreamingOrInPreview=%b",
+                    isUnlockedShade, mKeyguardShowing, mDreamingOrInPreview);
+            mBubbles.onStatusBarStateChanged(isUnlockedShade);
+        });
+    }
+
     private boolean isDreamingOrInPreview() {
         try {
             return mDreamManager.isDreamingOrInPreview();
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 15e0965..324d723 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -256,7 +256,7 @@
         });
         mCommandQueue.addCallback(new CommandQueue.Callbacks() {
             @Override
-            public void goToFullscreenFromSplit() {
+            public void moveFocusedTaskToFullscreen(int displayId) {
                 splitScreen.goToFullscreenFromSplit();
             }
         });
@@ -362,6 +362,12 @@
                 desktopMode.enterDesktop(displayId);
             }
         });
+        mCommandQueue.addCallback(new CommandQueue.Callbacks() {
+            @Override
+            public void moveFocusedTaskToFullscreen(int displayId) {
+                desktopMode.moveFocusedTaskToFullscreen(displayId);
+            }
+        });
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 3026966..3d0d8fb 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -21,8 +21,8 @@
 import android.view.ViewTreeObserver
 import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
 import com.android.systemui.Flags as AConfigFlags
+import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -319,7 +319,10 @@
     fun listenForDozeAmountTransition_updatesClockDozeAmount() =
         runBlocking(IMMEDIATE) {
             val transitionStep = MutableStateFlow(TransitionStep())
-            whenever(keyguardTransitionInteractor.dozeAmountTransition).thenReturn(transitionStep)
+            whenever(keyguardTransitionInteractor.lockscreenToAodTransition)
+                .thenReturn(transitionStep)
+            whenever(keyguardTransitionInteractor.aodToLockscreenTransition)
+                .thenReturn(transitionStep)
 
             val job = underTest.listenForDozeAmountTransition(this)
             transitionStep.value =
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
index d4522d0..93e7602 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
@@ -19,11 +19,14 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.hardware.biometrics.BiometricSourceType;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -119,4 +122,51 @@
         when(mKeyguardMessageArea.getText()).thenReturn(msg);
         assertThat(mMessageAreaController.getMessage()).isEqualTo(msg);
     }
+
+    @Test
+    public void testFingerprintMessageUpdate() {
+        String msg = "fpMessage";
+        mMessageAreaController.setMessage(
+                msg, BiometricSourceType.FINGERPRINT
+        );
+        verify(mKeyguardMessageArea).setMessage(msg, /* animate= */ true);
+
+        String msg2 = "fpMessage2";
+        mMessageAreaController.setMessage(
+                msg2, BiometricSourceType.FINGERPRINT
+        );
+        verify(mKeyguardMessageArea).setMessage(msg2, /* animate= */ true);
+    }
+
+    @Test
+    public void testFaceMessageDroppedWhileFingerprintMessageShowing() {
+        String fpMsg = "fpMessage";
+        mMessageAreaController.setMessage(
+                fpMsg, BiometricSourceType.FINGERPRINT
+        );
+        verify(mKeyguardMessageArea).setMessage(eq(fpMsg), /* animate= */ anyBoolean());
+
+        String faceMessage = "faceMessage";
+        mMessageAreaController.setMessage(
+                faceMessage, BiometricSourceType.FACE
+        );
+        verify(mKeyguardMessageArea, never())
+                .setMessage(eq(faceMessage), /* animate= */ anyBoolean());
+    }
+
+    @Test
+    public void testGenericMessageShowsAfterFingerprintMessageShowing() {
+        String fpMsg = "fpMessage";
+        mMessageAreaController.setMessage(
+                fpMsg, BiometricSourceType.FINGERPRINT
+        );
+        verify(mKeyguardMessageArea).setMessage(eq(fpMsg), /* animate= */ anyBoolean());
+
+        String genericMessage = "genericMessage";
+        mMessageAreaController.setMessage(
+                genericMessage, null
+        );
+        verify(mKeyguardMessageArea)
+                .setMessage(eq(genericMessage), /* animate= */ anyBoolean());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 538daee..336a97e 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -26,6 +26,8 @@
 import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
 import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
 import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID;
+import static android.telephony.SubscriptionManager.PROFILE_CLASS_DEFAULT;
+import static android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING;
 
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
@@ -187,6 +189,11 @@
             TEST_CARRIER, TEST_CARRIER_2, NAME_SOURCE_CARRIER_ID, 0xFFFFFF, "",
             DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", true, TEST_GROUP_UUID,
             TEST_CARRIER_ID, 0);
+    private static final SubscriptionInfo TEST_SUBSCRIPTION_PROVISIONING = new SubscriptionInfo(
+            1, "", 0,
+            TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_CARRIER_ID, 0xFFFFFF, "",
+            DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, TEST_GROUP_UUID,
+            TEST_CARRIER_ID, PROFILE_CLASS_PROVISIONING);
     private static final int FINGERPRINT_SENSOR_ID = 1;
 
     @Mock
@@ -1204,7 +1211,8 @@
         assertThat(mKeyguardUpdateMonitor.mSimDatas.get(TEST_SUBSCRIPTION.getSubscriptionId()))
                 .isNotNull();
 
-        when(mSubscriptionManager.getCompleteActiveSubscriptionInfoList()).thenReturn(null);
+        when(mSubscriptionManager.getCompleteActiveSubscriptionInfoList())
+                .thenReturn(new ArrayList<>());
         mKeyguardUpdateMonitor.mPhoneStateListener.onActiveDataSubscriptionIdChanged(
                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
         mTestableLooper.processAllMessages();
@@ -1216,6 +1224,37 @@
     }
 
     @Test
+    public void testActiveSubscriptionList_filtersProvisioningNetworks() {
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION_PROVISIONING);
+        when(mSubscriptionManager.getCompleteActiveSubscriptionInfoList()).thenReturn(list);
+        mKeyguardUpdateMonitor.mSubscriptionListener.onSubscriptionsChanged();
+
+        assertThat(mKeyguardUpdateMonitor.getSubscriptionInfo(true)).isEmpty();
+
+        SubscriptionInfo.Builder b = new SubscriptionInfo.Builder(TEST_SUBSCRIPTION_PROVISIONING);
+        b.setProfileClass(PROFILE_CLASS_DEFAULT);
+        SubscriptionInfo validInfo = b.build();
+
+        list.clear();
+        list.add(validInfo);
+        mKeyguardUpdateMonitor.mSubscriptionListener.onSubscriptionsChanged();
+
+        assertThat(mKeyguardUpdateMonitor.getSubscriptionInfo(true)).hasSize(1);
+    }
+
+    @Test
+    public void testActiveSubscriptionList_filtersProvisioningNetworks_untilValid() {
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION_PROVISIONING);
+        when(mSubscriptionManager.getCompleteActiveSubscriptionInfoList()).thenReturn(list);
+        mKeyguardUpdateMonitor.mSubscriptionListener.onSubscriptionsChanged();
+
+        assertThat(mKeyguardUpdateMonitor.getSubscriptionInfo(true)).isEmpty();
+
+    }
+
+    @Test
     public void testIsUserUnlocked() {
         // mUserManager will report the user as unlocked on @Before
         assertThat(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt
index 4ab7ab4..043dcaa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt
@@ -15,10 +15,13 @@
  */
 package com.android.systemui.battery
 
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.widget.ImageView
 import androidx.test.filters.SmallTest
+import com.android.settingslib.flags.Flags.FLAG_NEW_STATUS_BAR_ICONS
 import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.battery.BatteryMeterView.BatteryEstimateFetcher
@@ -141,7 +144,8 @@
     }
 
     @Test
-    fun changesFromEstimateToPercent_textAndContentDescriptionChanges() {
+    @DisableFlags(FLAG_NEW_STATUS_BAR_ICONS)
+    fun changesFromEstimateToPercent_textAndContentDescriptionChanges_flagOff() {
         mBatteryMeterView.onBatteryLevelChanged(15, false)
         mBatteryMeterView.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
         mBatteryMeterView.setBatteryEstimateFetcher(Fetcher())
@@ -164,6 +168,31 @@
     }
 
     @Test
+    @EnableFlags(FLAG_NEW_STATUS_BAR_ICONS)
+    fun changesFromEstimateToPercent_textAndContentDescriptionChanges_flagOn() {
+        mBatteryMeterView.onBatteryLevelChanged(15, false)
+        mBatteryMeterView.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
+        mBatteryMeterView.setBatteryEstimateFetcher(Fetcher())
+
+        mBatteryMeterView.updatePercentText()
+
+        assertThat(mBatteryMeterView.contentDescription).isEqualTo(
+            context.getString(
+                R.string.accessibility_battery_level_with_estimate, 15, ESTIMATE
+            )
+        )
+
+        // Update the show mode from estimate to percent
+        mBatteryMeterView.setPercentShowMode(BatteryMeterView.MODE_ON)
+
+        assertThat(mBatteryMeterView.batteryPercentView).isNull()
+        assertThat(mBatteryMeterView.contentDescription).isEqualTo(
+            context.getString(R.string.accessibility_battery_level, 15)
+        )
+        assertThat(mBatteryMeterView.unifiedBatteryState.showPercent).isTrue()
+    }
+
+    @Test
     fun contentDescription_manyUpdates_alwaysUpdated() {
         // BatteryDefender
         mBatteryMeterView.onBatteryLevelChanged(90, false)
@@ -208,7 +237,8 @@
     }
 
     @Test
-    fun isBatteryDefenderChanged_true_drawableGetsTrue() {
+    @DisableFlags(FLAG_NEW_STATUS_BAR_ICONS)
+    fun isBatteryDefenderChanged_true_drawableGetsTrue_flagOff() {
         mBatteryMeterView.setDisplayShieldEnabled(true)
         val drawable = getBatteryDrawable()
 
@@ -218,7 +248,18 @@
     }
 
     @Test
-    fun isBatteryDefenderChanged_false_drawableGetsFalse() {
+    @EnableFlags(FLAG_NEW_STATUS_BAR_ICONS)
+    fun isBatteryDefenderChanged_true_drawableGetsTrue_flagOn() {
+        mBatteryMeterView.setDisplayShieldEnabled(true)
+
+        mBatteryMeterView.onIsBatteryDefenderChanged(true)
+
+        assertThat(mBatteryMeterView.unifiedBatteryState.attribution).isNotNull()
+    }
+
+    @Test
+    @DisableFlags(FLAG_NEW_STATUS_BAR_ICONS)
+    fun isBatteryDefenderChanged_false_drawableGetsFalse_flagOff() {
         mBatteryMeterView.setDisplayShieldEnabled(true)
         val drawable = getBatteryDrawable()
 
@@ -232,7 +273,22 @@
     }
 
     @Test
-    fun isBatteryDefenderChanged_true_featureflagOff_drawableGetsFalse() {
+    @EnableFlags(FLAG_NEW_STATUS_BAR_ICONS)
+    fun isBatteryDefenderChanged_false_drawableGetsFalse_flagOn() {
+        mBatteryMeterView.setDisplayShieldEnabled(true)
+
+        // Start as true
+        mBatteryMeterView.onIsBatteryDefenderChanged(true)
+
+        // Update to false
+        mBatteryMeterView.onIsBatteryDefenderChanged(false)
+
+        assertThat(mBatteryMeterView.unifiedBatteryState.attribution).isNull()
+    }
+
+    @Test
+    @DisableFlags(FLAG_NEW_STATUS_BAR_ICONS)
+    fun isBatteryDefenderChanged_true_featureflagOff_drawableGetsFalse_flagOff() {
         mBatteryMeterView.setDisplayShieldEnabled(false)
         val drawable = getBatteryDrawable()
 
@@ -242,17 +298,41 @@
     }
 
     @Test
-    fun isIncompatibleChargingChanged_true_drawableGetsChargingFalse() {
+    @EnableFlags(FLAG_NEW_STATUS_BAR_ICONS)
+    fun isBatteryDefenderChanged_true_featureflagOff_drawableGetsFalse_flagOn() {
+        mBatteryMeterView.setDisplayShieldEnabled(false)
+
+        mBatteryMeterView.onIsBatteryDefenderChanged(true)
+
+        assertThat(mBatteryMeterView.unifiedBatteryState.attribution).isNull()
+    }
+
+    @Test
+    @DisableFlags(FLAG_NEW_STATUS_BAR_ICONS)
+    fun isIncompatibleChargingChanged_true_drawableGetsChargingFalse_flagOff() {
         mBatteryMeterView.onBatteryLevelChanged(45, true)
         val drawable = getBatteryDrawable()
 
         mBatteryMeterView.onIsIncompatibleChargingChanged(true)
 
         assertThat(drawable.getCharging()).isFalse()
+        assertThat(mBatteryMeterView.isCharging).isFalse()
     }
 
     @Test
-    fun isIncompatibleChargingChanged_false_drawableGetsChargingTrue() {
+    @EnableFlags(FLAG_NEW_STATUS_BAR_ICONS)
+    fun isIncompatibleChargingChanged_true_drawableGetsChargingFalse_flagOn() {
+        mBatteryMeterView.onBatteryLevelChanged(45, true)
+
+        mBatteryMeterView.onIsIncompatibleChargingChanged(true)
+
+        assertThat(mBatteryMeterView.unifiedBatteryState.attribution).isNull()
+        assertThat(mBatteryMeterView.isCharging).isFalse()
+    }
+
+    @Test
+    @DisableFlags(FLAG_NEW_STATUS_BAR_ICONS)
+    fun isIncompatibleChargingChanged_false_drawableGetsChargingTrue_flagOff() {
         mBatteryMeterView.onBatteryLevelChanged(45, true)
         val drawable = getBatteryDrawable()
 
@@ -261,6 +341,17 @@
         assertThat(drawable.getCharging()).isTrue()
     }
 
+    @Test
+    @EnableFlags(FLAG_NEW_STATUS_BAR_ICONS)
+    fun isIncompatibleChargingChanged_false_drawableGetsChargingTrue_flagOn() {
+        mBatteryMeterView.onBatteryLevelChanged(45, true)
+
+        mBatteryMeterView.onIsIncompatibleChargingChanged(false)
+
+        assertThat(mBatteryMeterView.isCharging).isTrue()
+        assertThat(mBatteryMeterView.unifiedBatteryState.attribution).isNotNull()
+    }
+
     private fun getBatteryDrawable(): AccessorizedBatteryDrawable {
         return (mBatteryMeterView.getChildAt(0) as ImageView)
                 .drawable as AccessorizedBatteryDrawable
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index 2c1a87d..10b86ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -21,8 +21,8 @@
 import android.hardware.biometrics.BiometricConstants
 import android.hardware.biometrics.BiometricManager
 import android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT
-import android.hardware.biometrics.Flags.customBiometricPrompt
 import android.hardware.biometrics.PromptInfo
+import android.hardware.biometrics.PromptVerticalListContentView
 import android.hardware.face.FaceSensorPropertiesInternal
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
 import android.os.Handler
@@ -40,7 +40,6 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.widget.LockPatternUtils
-import com.android.systemui.Flags.FLAG_CONSTRAINT_BP
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
 import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
@@ -148,8 +147,6 @@
 
     @Before
     fun setup() {
-        mSetFlagsRule.disableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
-        mSetFlagsRule.disableFlags(FLAG_CONSTRAINT_BP)
         displayRepository = FakeDisplayRepository()
 
         displayStateInteractor =
@@ -388,9 +385,10 @@
     }
 
     @Test
-    fun testShowCredentialUI() {
+    fun testShowCredentialUI_withDescription() {
+        mSetFlagsRule.disableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
         val container = initializeFingerprintContainer(
-            authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
+                authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
         )
         waitForIdleSync()
 
@@ -399,16 +397,12 @@
     }
 
     @Test
-    fun testShowBiometricUIWhenCustomBpEnabledAndNoSensors() {
-        mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
+    fun testShowCredentialUI_withCustomBp() {
         val container = initializeFingerprintContainer(
-                authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
+                authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL,
+                isUsingContentView = true
         )
-        waitForIdleSync()
-
-        assertThat(customBiometricPrompt()).isTrue()
-        assertThat(container.hasBiometricPrompt()).isTrue()
-        assertThat(container.hasCredentialView()).isFalse()
+        checkBpShowsForCredentialAndGoToCredential(container)
     }
 
     @Test
@@ -512,11 +506,13 @@
 
     private fun initializeFingerprintContainer(
         authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK,
-        addToView: Boolean = true
+        addToView: Boolean = true,
+        isUsingContentView: Boolean = false,
     ) = initializeContainer(
         TestAuthContainerView(
             authenticators = authenticators,
-            fingerprintProps = fingerprintSensorPropertiesInternal()
+            fingerprintProps = fingerprintSensorPropertiesInternal(),
+                isUsingContentView = isUsingContentView,
         ),
         addToView
     )
@@ -549,7 +545,8 @@
     private inner class TestAuthContainerView(
         authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK,
         fingerprintProps: List<FingerprintSensorPropertiesInternal> = listOf(),
-        faceProps: List<FaceSensorPropertiesInternal> = listOf()
+        faceProps: List<FaceSensorPropertiesInternal> = listOf(),
+        isUsingContentView: Boolean = false,
     ) : AuthContainerView(
         Config().apply {
             mContext = this@AuthContainerViewTest.context
@@ -559,6 +556,9 @@
             mSkipAnimation = true
             mPromptInfo = PromptInfo().apply {
                 this.authenticators = authenticators
+                if (isUsingContentView) {
+                    this.contentView = PromptVerticalListContentView.Builder().build()
+                }
             }
             mOpPackageName = OP_PACKAGE_NAME
         },
@@ -614,6 +614,17 @@
         val layoutParams = AuthContainerView.getLayoutParams(windowToken, "")
         assertThat((layoutParams.fitInsetsTypes and WindowInsets.Type.systemBars()) == 0).isTrue()
     }
+
+    private fun checkBpShowsForCredentialAndGoToCredential(container: TestAuthContainerView) {
+        waitForIdleSync()
+        assertThat(container.hasBiometricPrompt()).isTrue()
+        assertThat(container.hasCredentialView()).isFalse()
+
+        container.animateToCredentialUI(false)
+        waitForIdleSync()
+        assertThat(container.hasBiometricPrompt()).isFalse()
+        assertThat(container.hasCredentialView()).isTrue()
+    }
 }
 
 private fun AuthContainerView.hasBiometricPrompt() =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt
index 9f24d5d..f5e96c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt
@@ -237,6 +237,35 @@
         }
     }
 
+    @Test
+    fun providesTheCameraInfoOnCameraAvailableChange() {
+        testScope.runTest {
+            runCurrent()
+            collectLastValue(underTest.cameraInfo)
+
+            verify(faceManager).addAuthenticatorsRegisteredCallback(callback.capture())
+            callback.value.onAllAuthenticatorsRegistered(
+                listOf(createSensorProperties(1, SensorProperties.STRENGTH_STRONG))
+            )
+            runCurrent()
+            verify(cameraManager)
+                .registerAvailabilityCallback(any(Executor::class.java), cameraCallback.capture())
+
+            cameraCallback.value.onPhysicalCameraAvailable("0", PHYSICAL_CAMERA_ID_OUTER_FRONT)
+            runCurrent()
+
+            val cameraInfo by collectLastValue(underTest.cameraInfo)
+            assertThat(cameraInfo)
+                .isEqualTo(
+                    CameraInfo(
+                        "0",
+                        PHYSICAL_CAMERA_ID_OUTER_FRONT,
+                        Point(OUTER_FRONT_SENSOR_LOCATION[0], OUTER_FRONT_SENSOR_LOCATION[1])
+                    )
+                )
+        }
+    }
+
     private fun createSensorProperties(id: Int, strength: Int) =
         FaceSensorPropertiesInternal(id, strength, 0, emptyList(), 1, false, false, false)
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
index 47dc70f..dc438d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
@@ -83,13 +83,11 @@
             val strength by collectLastValue(repository.strength)
             val sensorType by collectLastValue(repository.sensorType)
             val sensorLocations by collectLastValue(repository.sensorLocations)
-            val propertiesInitialized by collectLastValue(repository.propertiesInitialized)
 
-            // Assert uninitialized properties.
-            assertThat(sensorId).isEqualTo(-2)
+            // Assert default properties.
+            assertThat(sensorId).isEqualTo(-1)
             assertThat(strength).isEqualTo(SensorStrength.CONVENIENCE)
             assertThat(sensorType).isEqualTo(FingerprintSensorType.UNKNOWN)
-            assertThat(propertiesInitialized).isEqualTo(false)
 
             val fingerprintProps =
                 listOf(
@@ -131,7 +129,6 @@
             assertThat(sensorId).isEqualTo(1)
             assertThat(strength).isEqualTo(SensorStrength.STRONG)
             assertThat(sensorType).isEqualTo(FingerprintSensorType.REAR)
-            assertThat(propertiesInitialized).isEqualTo(true)
 
             assertThat(sensorLocations?.size).isEqualTo(2)
             assertThat(sensorLocations).containsKey("display_id_1")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt
index b39e09d..7b972d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt
@@ -16,7 +16,9 @@
 
 package com.android.systemui.biometrics.data.repository
 
+import android.hardware.biometrics.BiometricManager
 import android.hardware.biometrics.PromptInfo
+import android.hardware.biometrics.PromptVerticalListContentView
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.AuthController
@@ -131,6 +133,52 @@
         }
 
     @Test
+    fun showBpWithoutIconForCredential_withCustomBp() =
+        testScope.runTest {
+            for (case in
+                listOf(
+                    PromptKind.Biometric(),
+                    PromptKind.Pin,
+                    PromptKind.Password,
+                    PromptKind.Pattern
+                )) {
+                val hasCredentialViewShown = case !is PromptKind.Biometric
+                val promptInfo =
+                    PromptInfo().apply {
+                        authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
+                        contentView = PromptVerticalListContentView.Builder().build()
+                    }
+                repository.setPrompt(promptInfo, USER_ID, CHALLENGE, case, OP_PACKAGE_NAME)
+                repository.setShouldShowBpWithoutIconForCredential(promptInfo)
+
+                assertThat(repository.showBpWithoutIconForCredential.value)
+                    .isEqualTo(!hasCredentialViewShown)
+            }
+        }
+
+    @Test
+    fun showBpWithoutIconForCredential_withDescription() =
+        testScope.runTest {
+            for (case in
+                listOf(
+                    PromptKind.Biometric(),
+                    PromptKind.Pin,
+                    PromptKind.Password,
+                    PromptKind.Pattern
+                )) {
+                val promptInfo =
+                    PromptInfo().apply {
+                        authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
+                        description = "description"
+                    }
+                repository.setPrompt(promptInfo, USER_ID, CHALLENGE, case, OP_PACKAGE_NAME)
+                repository.setShouldShowBpWithoutIconForCredential(promptInfo)
+
+                assertThat(repository.showBpWithoutIconForCredential.value).isFalse()
+            }
+        }
+
+    @Test
     fun setsAndUnsetsPrompt() =
         testScope.runTest {
             val kind = PromptKind.Pin
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
index 52b4275..2817780 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
@@ -147,7 +147,7 @@
         testScope.runTest { useCredentialAndReset(Utils.CREDENTIAL_PIN) }
 
     @Test
-    fun usePattermCredentialAndReset() =
+    fun usePatternCredentialAndReset() =
         testScope.runTest { useCredentialAndReset(Utils.CREDENTIAL_PATTERN) }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/compose/ComposeInitializerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/compose/ComposeInitializerTest.kt
index 3e6cc3b..03e4f9a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/compose/ComposeInitializerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/compose/ComposeInitializerTest.kt
@@ -32,10 +32,6 @@
 class ComposeInitializerTest : SysuiTestCase() {
     @Test
     fun testCanAddComposeViewInInitializedWindow() {
-        if (!ComposeFacade.isComposeAvailable()) {
-            return
-        }
-
         val root = TestWindowRoot(context)
         try {
             runOnMainThreadAndWaitForIdleSync { ViewUtils.attachView(root) }
@@ -55,12 +51,12 @@
     class TestWindowRoot(context: Context) : FrameLayout(context) {
         override fun onAttachedToWindow() {
             super.onAttachedToWindow()
-            ComposeFacade.composeInitializer().onAttachedToWindow(this)
+            ComposeInitializer.onAttachedToWindow(this)
         }
 
         override fun onDetachedFromWindow() {
             super.onDetachedFromWindow()
-            ComposeFacade.composeInitializer().onDetachedFromWindow(this)
+            ComposeInitializer.onDetachedFromWindow(this)
         }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt
index e30dd35d..e1e9fcb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt
@@ -25,6 +25,7 @@
 import com.android.keyguard.keyguardUpdateMonitor
 import com.android.keyguard.trustManager
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.CameraInfo
 import com.android.systemui.biometrics.data.repository.FaceSensorInfo
 import com.android.systemui.biometrics.data.repository.facePropertyRepository
 import com.android.systemui.biometrics.shared.model.LockoutMode
@@ -490,6 +491,47 @@
             verify(trustManager).clearAllBiometricRecognized(eq(BiometricSourceType.FACE), anyInt())
         }
 
+    @Test
+    fun faceAuthIsRequestedWhenAuthIsRunningWhileCameraInfoChanged() =
+        testScope.runTest {
+            facePropertyRepository.setCameraIno(null)
+            underTest.start()
+
+            faceAuthRepository.requestAuthenticate(
+                FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED,
+                true
+            )
+            facePropertyRepository.setCameraIno(CameraInfo("0", "1", null))
+
+            runCurrent()
+            assertThat(faceAuthRepository.runningAuthRequest.value)
+                .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_CAMERA_AVAILABLE_CHANGED, true))
+        }
+
+    @Test
+    fun faceAuthIsNotRequestedWhenNoAuthRunningWhileCameraInfoChanged() =
+        testScope.runTest {
+            facePropertyRepository.setCameraIno(null)
+            underTest.start()
+
+            facePropertyRepository.setCameraIno(CameraInfo("0", "1", null))
+
+            runCurrent()
+            assertThat(faceAuthRepository.runningAuthRequest.value).isNull()
+        }
+
+    @Test
+    fun faceAuthIsNotRequestedWhenAuthIsRunningWhileCameraInfoIsNull() =
+        testScope.runTest {
+            facePropertyRepository.setCameraIno(null)
+            underTest.start()
+
+            facePropertyRepository.setCameraIno(null)
+
+            runCurrent()
+            assertThat(faceAuthRepository.runningAuthRequest.value).isNull()
+        }
+
     companion object {
         private const val primaryUserId = 1
         private val primaryUser = UserInfo(primaryUserId, "test user", UserInfo.FLAG_PRIMARY)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
index e97edcb..9b8cf59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
@@ -27,7 +27,7 @@
 import com.android.systemui.flags.Flags.FULL_SCREEN_USER_SWITCHER
 import com.android.systemui.flags.fakeFeatureFlagsClassic
 import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionState
@@ -39,6 +39,7 @@
 import com.google.common.truth.Truth.assertThat
 import kotlin.test.Test
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.runner.RunWith
 
@@ -52,7 +53,7 @@
         }
     private val deviceEntryIconTransition = kosmos.fakeDeviceEntryIconViewModelTransition
     private val testScope = kosmos.testScope
-    private val keyguardRepository = kosmos.fakeKeyguardRepository
+    private val biometricSettingsRepository = kosmos.fakeBiometricSettingsRepository
     private val accessibilityRepository = kosmos.fakeAccessibilityRepository
     private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
     private val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
@@ -85,22 +86,12 @@
             setupVisibleStateOnLockscreen()
 
             // AOD
-            keyguardTransitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.LOCKSCREEN,
-                    to = KeyguardState.AOD,
-                    value = 0f,
-                    transitionState = TransitionState.STARTED,
-                )
+            keyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.LOCKSCREEN,
+                to = KeyguardState.AOD,
+                this,
             )
-            keyguardTransitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.LOCKSCREEN,
-                    to = KeyguardState.AOD,
-                    value = 1f,
-                    transitionState = TransitionState.FINISHED,
-                )
-            )
+            runCurrent()
             assertThat(visible).isFalse()
         }
     fun fpNotRunning_overlayNotVisible() =
@@ -129,6 +120,7 @@
 
         // Listening for UDFPS
         fingerprintPropertyRepository.supportsUdfps()
+        biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
         deviceEntryFingerprintAuthRepository.setIsRunning(true)
         deviceEntryRepository.setUnlocked(false)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java
index 9d9b263..2d3ca60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java
@@ -19,7 +19,13 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertNull;
 
+import static org.mockito.Mockito.when;
+
+import android.nearby.NearbyManager;
+import android.net.platform.flags.Flags;
 import android.os.PowerManager;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.testing.AndroidTestingRunner;
 
 import androidx.test.filters.SmallTest;
@@ -32,6 +38,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 
 @SmallTest
@@ -41,10 +48,13 @@
     ShutdownUi mShutdownUi;
     @Mock
     BlurUtils mBlurUtils;
+    @Mock
+    NearbyManager mNearbyManager;
 
     @Before
     public void setUp() throws Exception {
-        mShutdownUi = new ShutdownUi(getContext(), mBlurUtils);
+        MockitoAnnotations.initMocks(this);
+        mShutdownUi = new ShutdownUi(getContext(), mBlurUtils, mNearbyManager);
     }
 
     @Test
@@ -82,4 +92,53 @@
         String message = mShutdownUi.getReasonMessage("anything-else");
         assertNull(message);
     }
+
+    @EnableFlags(Flags.FLAG_POWERED_OFF_FINDING_PLATFORM)
+    @Test
+    public void getDialog_whenPowerOffFindingModeEnabled_returnsFinderDialog() {
+        when(mNearbyManager.getPoweredOffFindingMode()).thenReturn(
+                NearbyManager.POWERED_OFF_FINDING_MODE_ENABLED);
+
+        int actualLayout = mShutdownUi.getShutdownDialogContent(false);
+
+        int expectedLayout = com.android.systemui.res.R.layout.shutdown_dialog_finder_active;
+        assertEquals(actualLayout, expectedLayout);
+    }
+
+    @DisableFlags(Flags.FLAG_POWERED_OFF_FINDING_PLATFORM)
+    @Test
+    public void getDialog_whenPowerOffFindingModeEnabledFlagDisabled_returnsFinderDialog() {
+        when(mNearbyManager.getPoweredOffFindingMode()).thenReturn(
+                NearbyManager.POWERED_OFF_FINDING_MODE_ENABLED);
+
+        int actualLayout = mShutdownUi.getShutdownDialogContent(false);
+
+        int expectedLayout = R.layout.shutdown_dialog;
+        assertEquals(actualLayout, expectedLayout);
+    }
+
+    @EnableFlags(Flags.FLAG_POWERED_OFF_FINDING_PLATFORM)
+    @Test
+    public void getDialog_whenPowerOffFindingModeDisabled_returnsDefaultDialog() {
+        when(mNearbyManager.getPoweredOffFindingMode()).thenReturn(
+                NearbyManager.POWERED_OFF_FINDING_MODE_DISABLED);
+
+        int actualLayout = mShutdownUi.getShutdownDialogContent(false);
+
+        int expectedLayout = R.layout.shutdown_dialog;
+        assertEquals(actualLayout, expectedLayout);
+    }
+
+    @EnableFlags(Flags.FLAG_POWERED_OFF_FINDING_PLATFORM)
+    @Test
+    public void getDialog_whenPowerOffFindingModeEnabledAndIsReboot_returnsDefaultDialog() {
+        when(mNearbyManager.getPoweredOffFindingMode()).thenReturn(
+                NearbyManager.POWERED_OFF_FINDING_MODE_ENABLED);
+
+        int actualLayout = mShutdownUi.getShutdownDialogContent(true);
+
+        int expectedLayout = R.layout.shutdown_dialog;
+        assertEquals(actualLayout, expectedLayout);
+    }
+
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeysIndicatorCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeysIndicatorCoordinatorTest.kt
index a992956..59d8fc3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeysIndicatorCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeysIndicatorCoordinatorTest.kt
@@ -19,7 +19,6 @@
 import android.app.Dialog
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.compose.ComposeFacade
 import com.android.systemui.keyboard.data.repository.FakeStickyKeysRepository
 import com.android.systemui.keyboard.data.repository.keyboardRepository
 import com.android.systemui.keyboard.stickykeys.StickyKeysLogger
@@ -34,7 +33,6 @@
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
-import org.junit.Assume
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -54,19 +52,22 @@
 
     @Before
     fun setup() {
-        Assume.assumeTrue(ComposeFacade.isComposeAvailable())
         val dialogFactory = mock<StickyKeyDialogFactory>()
         whenever(dialogFactory.create(any())).thenReturn(dialog)
         val keyboardRepository = Kosmos().keyboardRepository
-        val viewModel = StickyKeysIndicatorViewModel(
+        val viewModel =
+            StickyKeysIndicatorViewModel(
                 stickyKeysRepository,
                 keyboardRepository,
-                testScope.backgroundScope)
-        coordinator = StickyKeysIndicatorCoordinator(
+                testScope.backgroundScope
+            )
+        coordinator =
+            StickyKeysIndicatorCoordinator(
                 testScope.backgroundScope,
                 dialogFactory,
                 viewModel,
-                mock<StickyKeysLogger>())
+                mock<StickyKeysLogger>()
+            )
         coordinator.startListening()
         keyboardRepository.setIsAnyKeyboardConnected(true)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
index 6d8e7aa..6aebe36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
@@ -126,7 +126,7 @@
             keyguardRepository.setKeyguardDismissible(true)
             runCurrent()
             shadeRepository.setCurrentFling(
-                FlingInfo(expand = true) // Not a dismiss fling (expand = true).
+                FlingInfo(expand = false) // Is a dismiss fling upward (expand = false).
             )
             runCurrent()
 
@@ -153,4 +153,22 @@
 
             assertThatRepository(transitionRepository).noTransitionsStarted()
         }
+
+    @Test
+    @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
+    fun testDoesNotTransitionToGone_whenDismissFling_emitsNull() =
+        testScope.runTest {
+            underTest.start()
+            verify(transitionRepository, never()).startTransition(any())
+
+            keyguardRepository.setKeyguardDismissible(true)
+            runCurrent()
+
+            // The fling is null when it a) initializes b) ends and in either case we should not
+            // swipe to unlock.
+            shadeRepository.setCurrentFling(null)
+            runCurrent()
+
+            assertThatRepository(transitionRepository).noTransitionsStarted()
+        }
 }
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 abd4238..c65a9ef 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
@@ -18,6 +18,7 @@
 
 import android.app.StatusBarManager
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.keyguard.KeyguardSecurityModel
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
 import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
@@ -25,8 +26,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
 import com.android.systemui.communal.domain.interactor.communalInteractor
-import com.android.systemui.communal.shared.model.CommunalSceneKey
-import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
+import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.fakeCommandQueue
@@ -129,7 +129,6 @@
 
         val glanceableHubTransitions =
             GlanceableHubTransitions(
-                scope = testScope,
                 bgDispatcher = kosmos.testDispatcher,
                 transitionInteractor = transitionInteractor,
                 transitionRepository = transitionRepository,
@@ -170,6 +169,7 @@
                     keyguardInteractor = keyguardInteractor,
                     transitionRepository = transitionRepository,
                     transitionInteractor = transitionInteractor,
+                    powerInteractor = powerInteractor,
                 )
                 .apply { start() }
 
@@ -575,8 +575,9 @@
             runCurrent()
 
             // WHEN the device begins to wake
+            keyguardRepository.setKeyguardShowing(true)
             powerInteractor.setAwakeForTest()
-            runCurrent()
+            advanceTimeBy(60L)
 
             assertThat(transitionRepository)
                 .startedTransition(
@@ -631,15 +632,66 @@
         }
 
     @Test
-    fun dozingToGone() =
+    fun dozingToGoneWithUnlock() =
         testScope.runTest {
             // GIVEN a prior transition has run to DOZING
             runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.DOZING)
+            runCurrent()
 
             // WHEN biometrics succeeds with wake and unlock mode
+            powerInteractor.setAwakeForTest()
             keyguardRepository.setBiometricUnlockState(BiometricUnlockModel.WAKE_AND_UNLOCK)
+            advanceTimeBy(60L)
+
+            assertThat(transitionRepository)
+                .startedTransition(
+                    to = KeyguardState.GONE,
+                    from = KeyguardState.DOZING,
+                    ownerName = "FromDozingTransitionInteractor",
+                    animatorAssertion = { it.isNotNull() }
+                )
+
+            coroutineContext.cancelChildren()
+        }
+
+    @Test
+    fun dozingToPrimaryBouncer() =
+        testScope.runTest {
+            // GIVEN a prior transition has run to DOZING
+            runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.DOZING)
             runCurrent()
 
+            // WHEN awaked by a request to show the primary bouncer, as can happen if SPFS is
+            // touched after boot
+            powerInteractor.setAwakeForTest()
+            bouncerRepository.setPrimaryShow(true)
+            advanceTimeBy(60L)
+
+            assertThat(transitionRepository)
+                .startedTransition(
+                    to = KeyguardState.PRIMARY_BOUNCER,
+                    from = KeyguardState.DOZING,
+                    ownerName = "FromDozingTransitionInteractor",
+                    animatorAssertion = { it.isNotNull() }
+                )
+
+            coroutineContext.cancelChildren()
+        }
+
+    /** This handles security method NONE and screen off with lock timeout */
+    @Test
+    fun dozingToGoneWithKeyguardNotShowing() =
+        testScope.runTest {
+            // GIVEN a prior transition has run to DOZING
+            runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.DOZING)
+            runCurrent()
+
+            // WHEN the device wakes up without a keyguard
+            keyguardRepository.setKeyguardShowing(false)
+            keyguardRepository.setKeyguardDismissible(true)
+            powerInteractor.setAwakeForTest()
+            advanceTimeBy(60L)
+
             assertThat(transitionRepository)
                 .startedTransition(
                     to = KeyguardState.GONE,
@@ -660,15 +712,16 @@
 
             // GIVEN the device is idle on the glanceable hub
             val idleTransitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal)
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(CommunalScenes.Communal)
                 )
             communalInteractor.setTransitionState(idleTransitionState)
             runCurrent()
 
             // WHEN the device begins to wake
+            keyguardRepository.setKeyguardShowing(true)
             powerInteractor.setAwakeForTest()
-            runCurrent()
+            advanceTimeBy(60L)
 
             assertThat(transitionRepository)
                 .startedTransition(
@@ -817,8 +870,8 @@
 
             // GIVEN the device is idle on the glanceable hub
             val idleTransitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal)
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(CommunalScenes.Communal)
                 )
             communalInteractor.setTransitionState(idleTransitionState)
             runCurrent()
@@ -966,8 +1019,8 @@
 
             // GIVEN the device is idle on the glanceable hub
             val idleTransitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal)
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(CommunalScenes.Communal)
                 )
             communalInteractor.setTransitionState(idleTransitionState)
             runCurrent()
@@ -1074,8 +1127,8 @@
 
             // GIVEN the device is idle on the glanceable hub
             val idleTransitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal)
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(CommunalScenes.Communal)
                 )
             communalInteractor.setTransitionState(idleTransitionState)
             runCurrent()
@@ -1109,8 +1162,8 @@
 
             // GIVEN the device is idle on the glanceable hub
             val idleTransitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal)
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(CommunalScenes.Communal)
                 )
             communalInteractor.setTransitionState(idleTransitionState)
             runCurrent()
@@ -1227,8 +1280,8 @@
 
             // GIVEN the device is idle on the glanceable hub
             val idleTransitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal)
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(CommunalScenes.Communal)
                 )
             communalInteractor.setTransitionState(idleTransitionState)
             runCurrent()
@@ -1336,8 +1389,9 @@
 
             // WHEN the keyguard is occluded and device wakes up
             keyguardRepository.setKeyguardOccluded(true)
+            keyguardRepository.setKeyguardShowing(true)
             powerInteractor.setAwakeForTest()
-            runCurrent()
+            advanceTimeBy(60L)
 
             // THEN a transition to OCCLUDED should occur
             assertThat(transitionRepository)
@@ -1415,13 +1469,13 @@
             runCurrent()
 
             // WHEN a transition to the glanceable hub starts
-            val currentScene = CommunalSceneKey.Blank
-            val targetScene = CommunalSceneKey.Communal
+            val currentScene = CommunalScenes.Blank
+            val targetScene = CommunalScenes.Communal
 
             val progress = MutableStateFlow(0f)
             val transitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Transition(
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Transition(
                         fromScene = currentScene,
                         toScene = targetScene,
                         progress = progress,
@@ -1594,13 +1648,13 @@
             runCurrent()
 
             // WHEN a glanceable hub transition starts
-            val currentScene = CommunalSceneKey.Blank
-            val targetScene = CommunalSceneKey.Communal
+            val currentScene = CommunalScenes.Blank
+            val targetScene = CommunalScenes.Communal
 
             val progress = MutableStateFlow(0f)
             val transitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Transition(
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Transition(
                         fromScene = currentScene,
                         toScene = targetScene,
                         progress = progress,
@@ -1625,8 +1679,8 @@
             clearInvocations(transitionRepository)
             runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.GLANCEABLE_HUB)
             val idleTransitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Idle(currentScene)
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(currentScene)
                 )
             communalInteractor.setTransitionState(idleTransitionState)
             runCurrent()
@@ -1650,13 +1704,13 @@
             runCurrent()
 
             // WHEN a transition away from glanceable hub starts
-            val currentScene = CommunalSceneKey.Communal
-            val targetScene = CommunalSceneKey.Blank
+            val currentScene = CommunalScenes.Communal
+            val targetScene = CommunalScenes.Blank
 
             val progress = MutableStateFlow(0f)
             val transitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Transition(
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Transition(
                         fromScene = currentScene,
                         toScene = targetScene,
                         progress = progress,
@@ -1680,8 +1734,8 @@
             clearInvocations(transitionRepository)
             runTransitionAndSetWakefulness(KeyguardState.GLANCEABLE_HUB, KeyguardState.LOCKSCREEN)
             val idleTransitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Idle(currentScene)
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(currentScene)
                 )
             communalInteractor.setTransitionState(idleTransitionState)
             runCurrent()
@@ -1767,8 +1821,8 @@
 
             // GIVEN the device is idle on the glanceable hub
             val idleTransitionState =
-                MutableStateFlow<ObservableCommunalTransitionState>(
-                    ObservableCommunalTransitionState.Idle(CommunalSceneKey.Communal)
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(CommunalScenes.Communal)
                 )
             communalInteractor.setTransitionState(idleTransitionState)
             runCurrent()
@@ -1812,26 +1866,40 @@
     @Test
     fun glanceableHubToDreaming() =
         testScope.runTest {
-            // GIVEN a device that is not dreaming or dozing
-            keyguardRepository.setDreamingWithOverlay(false)
+            // GIVEN that we are dreaming and not dozing
+            keyguardRepository.setDreaming(true)
             keyguardRepository.setDozeTransitionModel(
                 DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
             )
             runCurrent()
 
             // GIVEN a prior transition has run to GLANCEABLE_HUB
-            runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.GLANCEABLE_HUB)
+            runTransitionAndSetWakefulness(KeyguardState.DREAMING, KeyguardState.GLANCEABLE_HUB)
+            runCurrent()
 
-            // WHEN the device begins to dream
-            keyguardRepository.setDreamingWithOverlay(true)
-            advanceTimeBy(100L)
+            // WHEN a transition away from glanceable hub starts
+            val currentScene = CommunalScenes.Communal
+            val targetScene = CommunalScenes.Blank
+
+            val transitionState =
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Transition(
+                        fromScene = currentScene,
+                        toScene = targetScene,
+                        progress = flowOf(0f, 0.1f),
+                        isInitiatedByUserInput = false,
+                        isUserInputOngoing = flowOf(false),
+                    )
+                )
+            communalInteractor.setTransitionState(transitionState)
+            runCurrent()
 
             assertThat(transitionRepository)
                 .startedTransition(
                     ownerName = FromGlanceableHubTransitionInteractor::class.simpleName,
                     from = KeyguardState.GLANCEABLE_HUB,
                     to = KeyguardState.DREAMING,
-                    animatorAssertion = { it.isNotNull() },
+                    animatorAssertion = { it.isNull() }, // transition should be manually animated
                 )
 
             coroutineContext.cancelChildren()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
index a4483bd..6d605a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
@@ -375,4 +375,323 @@
                 values
             )
         }
+
+    @Test
+    fun testLockscreenVisibility_usesFromState_ifCanceled() =
+        testScope.runTest {
+            val values by collectValues(underTest.lockscreenVisibility)
+
+            transitionRepository.sendTransitionSteps(
+                from = KeyguardState.LOCKSCREEN,
+                to = KeyguardState.GONE,
+                testScope
+            )
+
+            runCurrent()
+
+            assertEquals(
+                listOf(
+                    // Initially should be true, as we start in LOCKSCREEN.
+                    true,
+                    // Then, false, since we finish in GONE.
+                    false,
+                ),
+                values
+            )
+
+            transitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                )
+            )
+            transitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.RUNNING,
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                )
+            )
+            runCurrent()
+
+            assertEquals(
+                listOf(
+                    true,
+                    // Should remain false as we transition from GONE.
+                    false,
+                ),
+                values
+            )
+
+            transitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.CANCELED,
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                )
+            )
+            transitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                    from = KeyguardState.AOD,
+                    to = KeyguardState.LOCKSCREEN,
+                )
+            )
+
+            runCurrent()
+
+            assertEquals(
+                listOf(
+                    true,
+                    false,
+                    // If we cancel and then go from LS -> GONE, we should immediately flip to the
+                    // visibility of the from state (LS).
+                    true,
+                ),
+                values
+            )
+
+            transitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.FINISHED,
+                    from = KeyguardState.AOD,
+                    to = KeyguardState.LOCKSCREEN,
+                )
+            )
+
+            runCurrent()
+
+            assertEquals(
+                listOf(
+                    true,
+                    false,
+                    true,
+                ),
+                values
+            )
+        }
+
+    /**
+     * Tests the special case for insecure camera launch. CANCELING a transition from GONE and then
+     * STARTING a transition back to GONE should never show the lockscreen, even though the current
+     * state during the AOD/isAsleep -> GONE transition is AOD (where lockscreen visibility = true).
+     */
+    @Test
+    fun testLockscreenVisibility_falseDuringTransitionToGone_fromCanceledGone() =
+        testScope.runTest {
+            val values by collectValues(underTest.lockscreenVisibility)
+
+            transitionRepository.sendTransitionSteps(
+                from = KeyguardState.LOCKSCREEN,
+                to = KeyguardState.GONE,
+                testScope
+            )
+
+            runCurrent()
+            assertEquals(
+                listOf(
+                    true,
+                    // Not visible since we're GONE.
+                    false,
+                ),
+                values
+            )
+
+            transitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                )
+            )
+            runCurrent()
+            transitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.RUNNING,
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                )
+            )
+            runCurrent()
+
+            transitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.CANCELED,
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                )
+            )
+            runCurrent()
+            transitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                    from = KeyguardState.AOD,
+                    to = KeyguardState.GONE,
+                )
+            )
+            runCurrent()
+
+            transitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.RUNNING,
+                    from = KeyguardState.AOD,
+                    to = KeyguardState.GONE,
+                )
+            )
+            runCurrent()
+            transitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.FINISHED,
+                    from = KeyguardState.AOD,
+                    to = KeyguardState.GONE,
+                )
+            )
+
+            runCurrent()
+            assertEquals(
+                listOf(
+                    true,
+                    // Remains not visible from GONE -> AOD (canceled) -> AOD since we never
+                    // FINISHED in AOD, and special-case handling for the insecure camera launch
+                    // ensures that we use the lockscreen visibility for GONE (false) if we're
+                    // STARTED to GONE after a CANCELED from GONE.
+                    false,
+                ),
+                values
+            )
+
+            transitionRepository.sendTransitionSteps(
+                from = KeyguardState.GONE,
+                to = KeyguardState.LOCKSCREEN,
+                testScope,
+            )
+
+            assertEquals(
+                listOf(
+                    true,
+                    false,
+                    // Make sure there's no stuck overrides or something - we should make lockscreen
+                    // visible again once we're finished in LOCKSCREEN.
+                    true,
+                ),
+                values
+            )
+        }
+
+    /**  */
+    @Test
+    fun testLockscreenVisibility_trueDuringTransitionToGone_fromNotCanceledGone() =
+        testScope.runTest {
+            val values by collectValues(underTest.lockscreenVisibility)
+
+            transitionRepository.sendTransitionSteps(
+                from = KeyguardState.LOCKSCREEN,
+                to = KeyguardState.GONE,
+                testScope
+            )
+
+            runCurrent()
+            assertEquals(
+                listOf(
+                    true,
+                    // Not visible when finished in GONE.
+                    false,
+                ),
+                values
+            )
+
+            transitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                )
+            )
+            runCurrent()
+            transitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.RUNNING,
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                )
+            )
+            runCurrent()
+
+            assertEquals(
+                listOf(
+                    true,
+                    // Still not visible during GONE -> AOD.
+                    false,
+                ),
+                values
+            )
+
+            transitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.FINISHED,
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                )
+            )
+            runCurrent()
+
+            assertEquals(
+                listOf(
+                    true,
+                    false,
+                    // Visible now that we're FINISHED in AOD.
+                    true
+                ),
+                values
+            )
+
+            transitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
+                    from = KeyguardState.AOD,
+                    to = KeyguardState.GONE,
+                )
+            )
+            runCurrent()
+
+            transitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.RUNNING,
+                    from = KeyguardState.AOD,
+                    to = KeyguardState.GONE,
+                )
+            )
+            runCurrent()
+
+            assertEquals(
+                listOf(
+                    true,
+                    false,
+                    // Remains visible from AOD during transition.
+                    true
+                ),
+                values
+            )
+
+            transitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.FINISHED,
+                    from = KeyguardState.AOD,
+                    to = KeyguardState.GONE,
+                )
+            )
+
+            runCurrent()
+            assertEquals(
+                listOf(
+                    true,
+                    false,
+                    true,
+                    // Until we're finished in GONE again.
+                    false
+                ),
+                values
+            )
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
index 17d602c..699284e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
@@ -18,16 +18,15 @@
 package com.android.systemui.keyguard.ui.view.layout.sections
 
 import android.graphics.Point
-import android.testing.TestableLooper
 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.Flags as AConfigFlags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.AuthController
-import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.FakeFeatureFlagsClassic
 import com.android.systemui.flags.Flags
@@ -52,9 +51,9 @@
 
 @ExperimentalCoroutinesApi
 @RunWith(JUnit4::class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
 @SmallTest
 class DefaultDeviceEntrySectionTest : SysuiTestCase() {
+    @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
@@ -62,12 +61,11 @@
     @Mock private lateinit var lockIconViewController: LockIconViewController
     @Mock private lateinit var falsingManager: FalsingManager
     private lateinit var underTest: DefaultDeviceEntrySection
-    private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
 
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
-        fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
+
         mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
 
         featureFlags =
@@ -75,6 +73,7 @@
         underTest =
             DefaultDeviceEntrySection(
                 TestScope().backgroundScope,
+                keyguardUpdateMonitor,
                 authController,
                 windowManager,
                 context,
@@ -92,7 +91,6 @@
     @Test
     fun addViewsConditionally_migrateFlagOn() {
         mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
-        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
         val constraintLayout = ConstraintLayout(context, null)
         underTest.addViews(constraintLayout)
         assertThat(constraintLayout.childCount).isGreaterThan(0)
@@ -104,9 +102,7 @@
         mSetFlagsRule.enableFlags(AConfigFlags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
         val constraintLayout = ConstraintLayout(context, null)
         underTest.addViews(constraintLayout)
-
-        // No views are added initially because fingerprint properties aren't initialized yet.
-        assertThat(constraintLayout.childCount).isEqualTo(0)
+        assertThat(constraintLayout.childCount).isGreaterThan(0)
     }
 
     @Test
@@ -134,7 +130,7 @@
     fun applyConstraints_udfps_refactor_on() {
         mSetFlagsRule.enableFlags(AConfigFlags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
         val cs = ConstraintSet()
-        underTest.applyConstraintsAfterPropertiesInitialized(cs, false)
+        underTest.applyConstraints(cs)
 
         val constraint = cs.getConstraint(R.id.device_entry_icon_view)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
new file mode 100644
index 0000000..4bb0d47
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.keyguardRepository
+import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel.Companion.UNLOCKED_DELAY_MS
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceEntryIconViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private lateinit var keyguardRepository: FakeKeyguardRepository
+    private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+    private lateinit var fingerprintAuthRepository: FakeDeviceEntryFingerprintAuthRepository
+    private lateinit var deviceEntryIconTransition: FakeDeviceEntryIconTransition
+    private lateinit var underTest: DeviceEntryIconViewModel
+
+    @Before
+    fun setUp() {
+        keyguardRepository = kosmos.fakeKeyguardRepository
+        fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
+        fingerprintAuthRepository = kosmos.fakeDeviceEntryFingerprintAuthRepository
+        deviceEntryIconTransition = kosmos.fakeDeviceEntryIconViewModelTransition
+        underTest = kosmos.deviceEntryIconViewModel
+    }
+
+    @Test
+    fun isLongPressEnabled_udfpsRunning() =
+        testScope.runTest {
+            val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled)
+            fingerprintPropertyRepository.supportsUdfps()
+            fingerprintAuthRepository.setIsRunning(true)
+            keyguardRepository.setKeyguardDismissible(false)
+            assertThat(isLongPressEnabled).isFalse()
+        }
+
+    @Test
+    fun isLongPressEnabled_unlocked() =
+        testScope.runTest {
+            val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled)
+            fingerprintPropertyRepository.supportsUdfps()
+            keyguardRepository.setKeyguardDismissible(true)
+            advanceTimeBy(UNLOCKED_DELAY_MS * 2) // wait for unlocked delay
+            runCurrent()
+            assertThat(isLongPressEnabled).isTrue()
+        }
+
+    @Test
+    fun isLongPressEnabled_lock() =
+        testScope.runTest {
+            val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled)
+            keyguardRepository.setKeyguardDismissible(false)
+
+            // udfps supported
+            fingerprintPropertyRepository.supportsUdfps()
+            assertThat(isLongPressEnabled).isTrue()
+
+            // udfps isn't supported
+            fingerprintPropertyRepository.supportsRearFps()
+            assertThat(isLongPressEnabled).isFalse()
+        }
+
+    @Test
+    fun isVisible() =
+        testScope.runTest {
+            val isVisible by collectLastValue(underTest.isVisible)
+            deviceEntryIconTransitionAlpha(1f)
+            assertThat(isVisible).isTrue()
+
+            deviceEntryIconTransitionAlpha(0f)
+            assertThat(isVisible).isFalse()
+
+            deviceEntryIconTransitionAlpha(.5f)
+            assertThat(isVisible).isTrue()
+        }
+
+    private fun deviceEntryIconTransitionAlpha(alpha: Float) {
+        deviceEntryIconTransition.setDeviceEntryParentViewAlpha(alpha)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/media/OWNERS
new file mode 100644
index 0000000..e6f218f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/src/com/android/systemui/media/OWNERS
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt
index 2e7829d..2f92afa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt
@@ -1247,7 +1247,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(com.android.settingslib.flags.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     fun bindBroadcastButton() {
         initMediaViewHolderMocks()
         initDeviceMediaData(true, APP_NAME)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt
index 45f49f0..29820f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt
@@ -28,7 +28,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.domain.interactor.communalInteractor
 import com.android.systemui.communal.domain.interactor.setCommunalAvailable
-import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.controls.controller.ControlsControllerImplTest.Companion.eq
 import com.android.systemui.dreams.DreamOverlayStateController
 import com.android.systemui.keyguard.WakefulnessLifecycle
@@ -514,7 +514,7 @@
             kosmos.setCommunalAvailable(true)
             runCurrent()
 
-            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+            communalInteractor.onSceneChanged(CommunalScenes.Communal)
             runCurrent()
             verify(mediaCarouselController)
                 .onDesiredLocationChanged(
@@ -526,7 +526,7 @@
                 )
             clearInvocations(mediaCarouselController)
 
-            communalInteractor.onSceneChanged(CommunalSceneKey.Blank)
+            communalInteractor.onSceneChanged(CommunalScenes.Blank)
             runCurrent()
             verify(mediaCarouselController)
                 .onDesiredLocationChanged(
@@ -549,7 +549,7 @@
             whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
 
             // UMO goes to communal even over the lock screen.
-            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+            communalInteractor.onSceneChanged(CommunalScenes.Communal)
             runCurrent()
             verify(mediaCarouselController)
                 .onDesiredLocationChanged(
@@ -571,7 +571,7 @@
             // Device is on lock screen.
             whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
 
-            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+            communalInteractor.onSceneChanged(CommunalScenes.Communal)
             runCurrent()
             verify(mediaCarouselController)
                 .onDesiredLocationChanged(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
index e2cf87a..0879884 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
@@ -28,6 +28,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.settingslib.flags.Flags;
 import com.android.settingslib.media.MediaOutputConstants;
 import com.android.systemui.SysuiTestCase;
 
@@ -84,7 +85,20 @@
     }
 
     @Test
+    public void launchMediaOutputBroadcastDialog_flagOff_broadcastDialogFactoryNotCalled() {
+        mSetFlagsRule.disableFlags(Flags.FLAG_LEGACY_LE_AUDIO_SHARING);
+        Intent intent = new Intent(
+                MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG);
+        intent.putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME, getContext().getPackageName());
+        mMediaOutputDialogReceiver.onReceive(getContext(), intent);
+
+        verify(mMockMediaOutputDialogFactory, never()).create(any(), anyBoolean(), any());
+        verify(mMockMediaOutputBroadcastDialogFactory, never()).create(any(), anyBoolean(), any());
+    }
+
+    @Test
     public void launchMediaOutputBroadcastDialog_ExtraPackageName_BroadcastDialogFactoryCalled() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_LEGACY_LE_AUDIO_SHARING);
         Intent intent = new Intent(
                 MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG);
         intent.putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME, getContext().getPackageName());
@@ -97,6 +111,7 @@
 
     @Test
     public void launchMediaOutputBroadcastDialog_WrongExtraKey_DialogBroadcastFactoryNotCalled() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_LEGACY_LE_AUDIO_SHARING);
         Intent intent = new Intent(
                 MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG);
         intent.putExtra("Wrong Package Name Key", getContext().getPackageName());
@@ -108,6 +123,7 @@
 
     @Test
     public void launchMediaOutputBroadcastDialog_NoExtra_BroadcastDialogFactoryNotCalled() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_LEGACY_LE_AUDIO_SHARING);
         Intent intent = new Intent(
                 MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG);
         mMediaOutputDialogReceiver.onReceive(getContext(), intent);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index d9ddc8e..84300da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -50,6 +50,7 @@
 import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.flags.Flags;
 import com.android.settingslib.media.LocalMediaManager;
 import com.android.settingslib.media.MediaDevice;
 import com.android.systemui.SysuiTestCase;
@@ -177,7 +178,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void getStopButtonVisibility_remoteBLEDevice_returnVisible() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -189,7 +190,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void getStopButtonVisibility_remoteNonBLEDevice_returnGone() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -210,7 +211,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void isBroadcastSupported_flagOnAndConnectBleDevice_returnsTrue() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -223,7 +224,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void isBroadcastSupported_flagOnAndNoBleDevice_returnsFalse() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -236,7 +237,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void isBroadcastSupported_notSupportBroadcastAndflagOn_returnsFalse() {
         FeatureFlagUtils.setEnabled(mContext,
                 FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
@@ -245,7 +246,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void isBroadcastSupported_flagOffAndConnectToBleDevice_returnsTrue() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -258,7 +259,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void isBroadcastSupported_flagOffAndNoBleDevice_returnsTrue() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -271,7 +272,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void isBroadcastSupported_noBleDeviceAndEnabledBroadcast_returnsTrue() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -284,7 +285,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void isBroadcastSupported_noBleDeviceAndDisabledBroadcast_returnsFalse() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -297,7 +298,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void getBroadcastIconVisibility_isBroadcasting_returnVisible() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -309,7 +310,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void getBroadcastIconVisibility_noBroadcasting_returnGone() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -321,7 +322,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void getBroadcastIconVisibility_remoteNonLeDevice_returnGone() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -374,7 +375,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void getStopButtonText_supportsBroadcast_returnsBroadcastText() {
         String stopText = mContext.getText(R.string.media_output_broadcast).toString();
         MediaDevice mMediaDevice = mock(MediaDevice.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/OWNERS
new file mode 100644
index 0000000..100dd2e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/OWNERS
new file mode 100644
index 0000000..f87d93a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/src/com/android/systemui/mediaprojection/OWNERS
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt
new file mode 100644
index 0000000..ac41073
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.appselector.view
+
+import android.app.ActivityOptions
+import android.app.IActivityTaskManager
+import android.os.Bundle
+import android.view.View
+import android.view.ViewGroup
+import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_PSS_APP_SELECTOR_ABRUPT_EXIT_FIX
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorResultHandler
+import com.android.systemui.mediaprojection.appselector.data.RecentTask
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Expect
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mockito.any
+import org.mockito.Mockito.verify
+
+@SmallTest
+class MediaProjectionRecentsViewControllerTest : SysuiTestCase() {
+
+    @get:Rule val expect: Expect = Expect.create()
+
+    private val recentTasksAdapter = mock<RecentTasksAdapter>()
+    private val tasksAdapterFactory = RecentTasksAdapter.Factory { _, _ -> recentTasksAdapter }
+    private val taskViewSizeProvider = mock<TaskPreviewSizeProvider>()
+    private val activityTaskManager = mock<IActivityTaskManager>()
+    private val resultHandler = mock<MediaProjectionAppSelectorResultHandler>()
+    private val bundleCaptor = ArgumentCaptor.forClass(Bundle::class.java)
+
+    private val task =
+        RecentTask(
+            taskId = 123,
+            displayId = 456,
+            userId = 789,
+            topActivityComponent = null,
+            baseIntentComponent = null,
+            colorBackground = null,
+            isForegroundTask = false
+        )
+
+    private val taskView =
+        View(context).apply {
+            layoutParams = ViewGroup.LayoutParams(/* width = */ 100, /* height = */ 200)
+        }
+
+    private val controller =
+        MediaProjectionRecentsViewController(
+            tasksAdapterFactory,
+            taskViewSizeProvider,
+            activityTaskManager,
+            resultHandler
+        )
+
+    @Test
+    fun onRecentAppClicked_taskWithSameIdIsStartedFromRecents() {
+        controller.onRecentAppClicked(task, taskView)
+
+        verify(activityTaskManager).startActivityFromRecents(eq(task.taskId), any())
+    }
+
+    @Test
+    fun onRecentAppClicked_launchDisplayIdIsSet() {
+        controller.onRecentAppClicked(task, taskView)
+
+        assertThat(getStartedTaskActivityOptions().launchDisplayId).isEqualTo(task.displayId)
+    }
+
+    @Test
+    fun onRecentAppClicked_taskNotInForeground_usesScaleUpAnimation() {
+        controller.onRecentAppClicked(task, taskView)
+
+        assertThat(getStartedTaskActivityOptions().animationType)
+            .isEqualTo(ActivityOptions.ANIM_SCALE_UP)
+    }
+
+    @Test
+    fun onRecentAppClicked_taskInForeground_flagOff_usesScaleUpAnimation() {
+        mSetFlagsRule.disableFlags(FLAG_PSS_APP_SELECTOR_ABRUPT_EXIT_FIX)
+
+        controller.onRecentAppClicked(task, taskView)
+
+        assertThat(getStartedTaskActivityOptions().animationType)
+            .isEqualTo(ActivityOptions.ANIM_SCALE_UP)
+    }
+
+    @Test
+    fun onRecentAppClicked_taskInForeground_flagOn_usesDefaultAnimation() {
+        mSetFlagsRule.enableFlags(FLAG_PSS_APP_SELECTOR_ABRUPT_EXIT_FIX)
+        val foregroundTask = task.copy(isForegroundTask = true)
+
+        controller.onRecentAppClicked(foregroundTask, taskView)
+
+        expect
+            .that(getStartedTaskActivityOptions().animationType)
+            .isEqualTo(ActivityOptions.ANIM_CUSTOM)
+        expect.that(getStartedTaskActivityOptions().overrideTaskTransition).isTrue()
+        expect
+            .that(getStartedTaskActivityOptions().customExitResId)
+            .isEqualTo(com.android.internal.R.anim.resolver_close_anim)
+        expect.that(getStartedTaskActivityOptions().customEnterResId).isEqualTo(0)
+    }
+
+    private fun getStartedTaskActivityOptions(): ActivityOptions {
+        verify(activityTaskManager)
+            .startActivityFromRecents(eq(task.taskId), bundleCaptor.capture())
+        return ActivityOptions.fromBundle(bundleCaptor.value)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt
deleted file mode 100644
index e044eec..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.mediaprojection.permission
-
-import android.app.AlertDialog
-import android.media.projection.MediaProjectionConfig
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.view.WindowManager
-import android.widget.Spinner
-import android.widget.TextView
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.flags.FeatureFlagsClassic
-import com.android.systemui.flags.Flags
-import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
-import com.android.systemui.res.R
-import com.android.systemui.statusbar.phone.AlertDialogWithDelegate
-import com.android.systemui.statusbar.phone.SystemUIDialog
-import com.android.systemui.util.mockito.mock
-import junit.framework.Assert.assertEquals
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito.`when` as whenever
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-class MediaProjectionPermissionDialogDelegateTest : SysuiTestCase() {
-
-    private lateinit var dialog: AlertDialog
-
-    private val flags = mock<FeatureFlagsClassic>()
-    private val onStartRecordingClicked = mock<Runnable>()
-    private val mediaProjectionMetricsLogger = mock<MediaProjectionMetricsLogger>()
-
-    private val mediaProjectionConfig: MediaProjectionConfig =
-        MediaProjectionConfig.createConfigForDefaultDisplay()
-    private val appName: String = "testApp"
-    private val hostUid: Int = 12345
-
-    private val resIdSingleApp = R.string.screen_share_permission_dialog_option_single_app
-    private val resIdFullScreen = R.string.screen_share_permission_dialog_option_entire_screen
-    private val resIdSingleAppDisabled =
-        R.string.media_projection_entry_app_permission_dialog_single_app_disabled
-
-    @Before
-    fun setUp() {
-        whenever(flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)).thenReturn(true)
-    }
-
-    @After
-    fun teardown() {
-        if (::dialog.isInitialized) {
-            dialog.dismiss()
-        }
-    }
-
-    @Test
-    fun showDialog_forceShowPartialScreenShareFalse() {
-        // Set up dialog with MediaProjectionConfig.createConfigForDefaultDisplay() and
-        // overrideDisableSingleAppOption = false
-        val overrideDisableSingleAppOption = false
-        setUpAndShowDialog(overrideDisableSingleAppOption)
-
-        val spinner = dialog.requireViewById<Spinner>(R.id.screen_share_mode_spinner)
-        val secondOptionText =
-            spinner.adapter
-                .getDropDownView(1, null, spinner)
-                .findViewById<TextView>(android.R.id.text2)
-                ?.text
-
-        // check that the first option is full screen and enabled
-        assertEquals(context.getString(resIdFullScreen), spinner.selectedItem)
-
-        // check that the second option is single app and disabled
-        assertEquals(context.getString(resIdSingleAppDisabled, appName), secondOptionText)
-    }
-
-    @Test
-    fun showDialog_forceShowPartialScreenShareTrue() {
-        // Set up dialog with MediaProjectionConfig.createConfigForDefaultDisplay() and
-        // overrideDisableSingleAppOption = true
-        val overrideDisableSingleAppOption = true
-        setUpAndShowDialog(overrideDisableSingleAppOption)
-
-        val spinner = dialog.requireViewById<Spinner>(R.id.screen_share_mode_spinner)
-        val secondOptionText =
-            spinner.adapter
-                .getDropDownView(1, null, spinner)
-                .findViewById<TextView>(android.R.id.text1)
-                ?.text
-
-        // check that the first option is single app and enabled
-        assertEquals(context.getString(resIdSingleApp), spinner.selectedItem)
-
-        // check that the second option is full screen and enabled
-        assertEquals(context.getString(resIdFullScreen), secondOptionText)
-    }
-
-    private fun setUpAndShowDialog(overrideDisableSingleAppOption: Boolean) {
-        val delegate =
-            MediaProjectionPermissionDialogDelegate(
-                context,
-                mediaProjectionConfig,
-                {},
-                onStartRecordingClicked,
-                appName,
-                overrideDisableSingleAppOption,
-                hostUid,
-                mediaProjectionMetricsLogger
-            )
-
-        dialog = AlertDialogWithDelegate(context, R.style.Theme_SystemUI_Dialog, delegate)
-        SystemUIDialog.applyFlags(dialog)
-        SystemUIDialog.setDialogSize(dialog)
-
-        dialog.window?.addSystemFlags(
-            WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS
-        )
-
-        delegate.onCreate(dialog, savedInstanceState = null)
-        dialog.show()
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt
index 83932b0..dbfab64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt
@@ -49,6 +49,19 @@
         )
 
     @Test
+    fun launchRecentTask_taskIsMovedToForeground() =
+        testScope.runTest {
+            val currentForegroundTask by collectLastValue(repo.foregroundTask)
+            val newForegroundTask = createTask(taskId = 1)
+            val backgroundTask = createTask(taskId = 2)
+            fakeActivityTaskManager.addRunningTasks(backgroundTask, newForegroundTask)
+
+            repo.launchRecentTask(newForegroundTask)
+
+            assertThat(currentForegroundTask).isEqualTo(newForegroundTask)
+        }
+
+    @Test
     fun findRunningTaskFromWindowContainerToken_noMatch_returnsNull() {
         fakeActivityTaskManager.addRunningTasks(createTask(taskId = 1), createTask(taskId = 2))
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeActivityTaskManager.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeActivityTaskManager.kt
index 1c4870b..920e5ee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeActivityTaskManager.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeActivityTaskManager.kt
@@ -17,7 +17,7 @@
 package com.android.systemui.mediaprojection.taskswitcher.data.repository
 
 import android.app.ActivityManager.RunningTaskInfo
-import android.app.ActivityTaskManager
+import android.app.IActivityTaskManager
 import android.app.TaskStackListener
 import android.content.Intent
 import android.window.IWindowContainerToken
@@ -31,7 +31,7 @@
     private val runningTasks = mutableListOf<RunningTaskInfo>()
     private val taskTaskListeners = mutableListOf<TaskStackListener>()
 
-    val activityTaskManager = mock<ActivityTaskManager>()
+    val activityTaskManager = mock<IActivityTaskManager>()
 
     init {
         whenever(activityTaskManager.registerTaskStackListener(any())).thenAnswer {
@@ -42,10 +42,20 @@
             taskTaskListeners -= it.arguments[0] as TaskStackListener
             return@thenAnswer Unit
         }
-        whenever(activityTaskManager.getTasks(any())).thenAnswer {
+        whenever(activityTaskManager.getTasks(any(), any(), any(), any())).thenAnswer {
             val maxNumTasks = it.arguments[0] as Int
             return@thenAnswer runningTasks.take(maxNumTasks)
         }
+        whenever(activityTaskManager.startActivityFromRecents(any(), any())).thenAnswer {
+            val taskId = it.arguments[0] as Int
+            val runningTask = runningTasks.find { runningTask -> runningTask.taskId == taskId }
+            if (runningTask != null) {
+                moveTaskToForeground(runningTask)
+                return@thenAnswer 0
+            } else {
+                return@thenAnswer -1
+            }
+        }
     }
 
     fun moveTaskToForeground(task: RunningTaskInfo) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeMediaProjectionManager.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeMediaProjectionManager.kt
index 44c411f..28393e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeMediaProjectionManager.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeMediaProjectionManager.kt
@@ -22,6 +22,8 @@
 import android.os.IBinder
 import android.os.UserHandle
 import android.view.ContentRecordingSession
+import android.window.WindowContainerToken
+import com.android.systemui.mediaprojection.MediaProjectionServiceHelper
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
@@ -29,6 +31,7 @@
 class FakeMediaProjectionManager {
 
     val mediaProjectionManager = mock<MediaProjectionManager>()
+    val helper = mock<MediaProjectionServiceHelper>()
 
     private val callbacks = mutableListOf<MediaProjectionManager.Callback>()
 
@@ -41,6 +44,11 @@
             callbacks -= it.arguments[0] as MediaProjectionManager.Callback
             return@thenAnswer Unit
         }
+        whenever(helper.updateTaskRecordingSession(any())).thenAnswer {
+            val token = it.arguments[0] as WindowContainerToken
+            dispatchOnSessionSet(session = createSingleTaskSession(token.asBinder()))
+            return@thenAnswer true
+        }
     }
 
     fun dispatchOnStart(info: MediaProjectionInfo = DEFAULT_INFO) {
@@ -61,6 +69,7 @@
     companion object {
         fun createDisplaySession(): ContentRecordingSession =
             ContentRecordingSession.createDisplaySession(/* displayToMirror = */ 123)
+
         fun createSingleTaskSession(token: IBinder = Binder()): ContentRecordingSession =
             ContentRecordingSession.createTaskSession(token)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepositoryTest.kt
index 7bd97ce..fdd434a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepositoryTest.kt
@@ -28,9 +28,8 @@
 import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager.Companion.createToken
 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.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -40,7 +39,7 @@
 @SmallTest
 class MediaProjectionManagerRepositoryTest : SysuiTestCase() {
 
-    private val dispatcher = StandardTestDispatcher()
+    private val dispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(dispatcher)
 
     private val fakeMediaProjectionManager = FakeMediaProjectionManager()
@@ -58,14 +57,27 @@
             mediaProjectionManager = fakeMediaProjectionManager.mediaProjectionManager,
             handler = Handler.getMain(),
             applicationScope = testScope.backgroundScope,
-            tasksRepository = tasksRepo
+            tasksRepository = tasksRepo,
+            backgroundDispatcher = dispatcher,
+            mediaProjectionServiceHelper = fakeMediaProjectionManager.helper
         )
 
     @Test
+    fun switchProjectedTask_stateIsUpdatedWithNewTask() =
+        testScope.runTest {
+            val task = createTask(taskId = 1)
+            val state by collectLastValue(repo.mediaProjectionState)
+
+            fakeActivityTaskManager.addRunningTasks(task)
+            repo.switchProjectedTask(task)
+
+            assertThat(state).isEqualTo(MediaProjectionState.SingleTask(task))
+        }
+
+    @Test
     fun mediaProjectionState_onStart_emitsNotProjecting() =
         testScope.runTest {
             val state by collectLastValue(repo.mediaProjectionState)
-            runCurrent()
 
             fakeMediaProjectionManager.dispatchOnStart()
 
@@ -76,7 +88,6 @@
     fun mediaProjectionState_onStop_emitsNotProjecting() =
         testScope.runTest {
             val state by collectLastValue(repo.mediaProjectionState)
-            runCurrent()
 
             fakeMediaProjectionManager.dispatchOnStop()
 
@@ -87,7 +98,6 @@
     fun mediaProjectionState_onSessionSet_sessionNull_emitsNotProjecting() =
         testScope.runTest {
             val state by collectLastValue(repo.mediaProjectionState)
-            runCurrent()
 
             fakeMediaProjectionManager.dispatchOnSessionSet(session = null)
 
@@ -98,7 +108,6 @@
     fun mediaProjectionState_onSessionSet_contentToRecordDisplay_emitsEntireScreen() =
         testScope.runTest {
             val state by collectLastValue(repo.mediaProjectionState)
-            runCurrent()
 
             fakeMediaProjectionManager.dispatchOnSessionSet(
                 session = ContentRecordingSession.createDisplaySession(/* displayToMirror= */ 123)
@@ -111,7 +120,6 @@
     fun mediaProjectionState_sessionSet_taskWithToken_noMatchingRunningTask_emitsEntireScreen() =
         testScope.runTest {
             val state by collectLastValue(repo.mediaProjectionState)
-            runCurrent()
 
             val taskWindowContainerToken = Binder()
             fakeMediaProjectionManager.dispatchOnSessionSet(
@@ -128,7 +136,6 @@
             val task = createTask(taskId = 1, token = token)
             fakeActivityTaskManager.addRunningTasks(task)
             val state by collectLastValue(repo.mediaProjectionState)
-            runCurrent()
 
             fakeMediaProjectionManager.dispatchOnSessionSet(
                 session = ContentRecordingSession.createTaskSession(token.asBinder())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt
index b2ebe1bc..dfb688b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt
@@ -61,6 +61,8 @@
             handler = Handler.getMain(),
             applicationScope = testScope.backgroundScope,
             tasksRepository = tasksRepo,
+            backgroundDispatcher = dispatcher,
+            mediaProjectionServiceHelper = fakeMediaProjectionManager.helper,
         )
 
     private val interactor = TaskSwitchInteractor(mediaRepo, tasksRepo)
@@ -118,6 +120,40 @@
         }
 
     @Test
+    fun taskSwitchChanges_projectingTask_foregroundTaskDifferent_thenSwitched_emitsUnchanged() =
+        testScope.runTest {
+            val projectedTask = createTask(taskId = 0)
+            val foregroundTask = createTask(taskId = 1)
+            val taskSwitchState by collectLastValue(interactor.taskSwitchChanges)
+
+            fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask)
+            fakeMediaProjectionManager.dispatchOnSessionSet(
+                session = createSingleTaskSession(token = projectedTask.token.asBinder())
+            )
+            fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
+            interactor.switchProjectedTask(foregroundTask)
+
+            assertThat(taskSwitchState).isEqualTo(TaskSwitchState.TaskUnchanged)
+        }
+
+    @Test
+    fun taskSwitchChanges_projectingTask_foregroundTaskDifferent_thenWentBack_emitsUnchanged() =
+        testScope.runTest {
+            val projectedTask = createTask(taskId = 0)
+            val foregroundTask = createTask(taskId = 1)
+            val taskSwitchState by collectLastValue(interactor.taskSwitchChanges)
+
+            fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask)
+            fakeMediaProjectionManager.dispatchOnSessionSet(
+                session = createSingleTaskSession(token = projectedTask.token.asBinder())
+            )
+            fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
+            interactor.goBackToTask(projectedTask)
+
+            assertThat(taskSwitchState).isEqualTo(TaskSwitchState.TaskUnchanged)
+        }
+
+    @Test
     fun taskSwitchChanges_projectingTask_foregroundTaskLauncher_emitsTaskUnchanged() =
         testScope.runTest {
             val projectedTask = createTask(taskId = 0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinatorTest.kt
index d0c6d7c..c4e9393 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinatorTest.kt
@@ -21,14 +21,15 @@
 import android.os.Handler
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.mediaprojection.taskswitcher.data.repository.ActivityTaskManagerTasksRepository
 import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager.Companion.createTask
 import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeMediaProjectionManager
 import com.android.systemui.mediaprojection.taskswitcher.data.repository.MediaProjectionManagerRepository
 import com.android.systemui.mediaprojection.taskswitcher.domain.interactor.TaskSwitchInteractor
 import com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel.TaskSwitcherNotificationViewModel
+import com.android.systemui.res.R
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.mock
@@ -42,6 +43,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
+import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -49,7 +51,7 @@
 @SmallTest
 class TaskSwitcherNotificationCoordinatorTest : SysuiTestCase() {
 
-    private val notificationManager: NotificationManager = mock()
+    private val notificationManager = mock<NotificationManager>()
 
     private val dispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(dispatcher)
@@ -70,22 +72,26 @@
             handler = Handler.getMain(),
             applicationScope = testScope.backgroundScope,
             tasksRepository = tasksRepo,
+            backgroundDispatcher = dispatcher,
+            mediaProjectionServiceHelper = fakeMediaProjectionManager.helper,
         )
 
     private val interactor = TaskSwitchInteractor(mediaRepo, tasksRepo)
-    private val viewModel = TaskSwitcherNotificationViewModel(interactor)
+    private val viewModel =
+        TaskSwitcherNotificationViewModel(interactor, backgroundDispatcher = dispatcher)
 
-    private val coordinator =
-        TaskSwitcherNotificationCoordinator(
-            context,
-            notificationManager,
-            testScope.backgroundScope,
-            dispatcher,
-            viewModel
-        )
+    private lateinit var coordinator: TaskSwitcherNotificationCoordinator
 
     @Before
     fun setup() {
+        coordinator =
+            TaskSwitcherNotificationCoordinator(
+                context,
+                notificationManager,
+                testScope.backgroundScope,
+                viewModel,
+                fakeBroadcastDispatcher,
+            )
         coordinator.start()
     }
 
@@ -105,7 +111,7 @@
         testScope.runTest {
             fakeMediaProjectionManager.dispatchOnStop()
 
-            verify(notificationManager).cancel(any())
+            verify(notificationManager).cancel(any(), any())
         }
     }
 
@@ -114,7 +120,7 @@
         testScope.runTest {
             fakeMediaProjectionManager.dispatchOnStop()
             val idCancel = argumentCaptor<Int>()
-            verify(notificationManager).cancel(idCancel.capture())
+            verify(notificationManager).cancel(any(), idCancel.capture())
 
             switchTask()
             val idNotify = argumentCaptor<Int>()
@@ -124,9 +130,55 @@
         }
     }
 
+    @Test
+    fun switchTaskAction_hidesNotification() =
+        testScope.runTest {
+            switchTask()
+            val notification = argumentCaptor<Notification>()
+            verify(notificationManager).notify(any(), any(), notification.capture())
+            verify(notificationManager, never()).cancel(any(), any())
+
+            val action = findSwitchAction(notification.value)
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+                context,
+                action.actionIntent.intent
+            )
+
+            verify(notificationManager).cancel(any(), any())
+        }
+
+    @Test
+    fun goBackAction_hidesNotification() =
+        testScope.runTest {
+            switchTask()
+            val notification = argumentCaptor<Notification>()
+            verify(notificationManager).notify(any(), any(), notification.capture())
+            verify(notificationManager, never()).cancel(any(), any())
+
+            val action = findGoBackAction(notification.value)
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+                context,
+                action.actionIntent.intent
+            )
+
+            verify(notificationManager).cancel(any(), any())
+        }
+
+    private fun findSwitchAction(notification: Notification): Notification.Action {
+        return notification.actions.first {
+            it.title == context.getString(R.string.media_projection_task_switcher_action_switch)
+        }
+    }
+
+    private fun findGoBackAction(notification: Notification): Notification.Action {
+        return notification.actions.first {
+            it.title == context.getString(R.string.media_projection_task_switcher_action_back)
+        }
+    }
+
     private fun switchTask() {
-        val projectedTask = FakeActivityTaskManager.createTask(taskId = 1)
-        val foregroundTask = FakeActivityTaskManager.createTask(taskId = 2)
+        val projectedTask = createTask(taskId = 1)
+        val foregroundTask = createTask(taskId = 2)
         fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask)
         fakeMediaProjectionManager.dispatchOnSessionSet(
             session =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModelTest.kt
index 7d38de4..5dadf21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModelTest.kt
@@ -63,11 +63,14 @@
             handler = Handler.getMain(),
             applicationScope = testScope.backgroundScope,
             tasksRepository = tasksRepo,
+            backgroundDispatcher = dispatcher,
+            mediaProjectionServiceHelper = fakeMediaProjectionManager.helper,
         )
 
     private val interactor = TaskSwitchInteractor(mediaRepo, tasksRepo)
 
-    private val viewModel = TaskSwitcherNotificationViewModel(interactor)
+    private val viewModel =
+        TaskSwitcherNotificationViewModel(interactor, backgroundDispatcher = dispatcher)
 
     @Test
     fun uiState_notProjecting_emitsNotShowing() =
@@ -135,6 +138,40 @@
         }
 
     @Test
+    fun uiState_projectingTask_foregroundTaskChanged_thenTaskSwitched_emitsNotShowing() =
+        testScope.runTest {
+            val projectedTask = createTask(taskId = 1)
+            val foregroundTask = createTask(taskId = 2)
+            val uiState by collectLastValue(viewModel.uiState)
+
+            fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask)
+            fakeMediaProjectionManager.dispatchOnSessionSet(
+                session = createSingleTaskSession(projectedTask.token.asBinder())
+            )
+            fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
+            viewModel.onSwitchTaskClicked(foregroundTask)
+
+            assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing)
+        }
+
+    @Test
+    fun uiState_projectingTask_foregroundTaskChanged_thenGoBack_emitsNotShowing() =
+        testScope.runTest {
+            val projectedTask = createTask(taskId = 1)
+            val foregroundTask = createTask(taskId = 2)
+            val uiState by collectLastValue(viewModel.uiState)
+
+            fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask)
+            fakeMediaProjectionManager.dispatchOnSessionSet(
+                session = createSingleTaskSession(projectedTask.token.asBinder())
+            )
+            fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
+            viewModel.onGoBackToTaskClicked(projectedTask)
+
+            assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing)
+        }
+
+    @Test
     fun uiState_projectingTask_foregroundTaskChanged_same_emitsNotShowing() =
         testScope.runTest {
             val projectedTask = createTask(taskId = 1)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegateTest.kt
new file mode 100644
index 0000000..8ecb953
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegateTest.kt
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.dialog.bluetooth
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.LayoutInflater
+import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.UiEventLogger
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.DialogTransitionAnimator
+import com.android.systemui.model.SysUiState
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.test.TestCoroutineScheduler
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class BluetoothTileDialogDelegateTest : SysuiTestCase() {
+    companion object {
+        const val DEVICE_NAME = "device"
+        const val DEVICE_CONNECTION_SUMMARY = "active"
+        const val ENABLED = true
+        const val CONTENT_HEIGHT = WRAP_CONTENT
+    }
+
+    @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
+
+    @Mock private lateinit var cachedBluetoothDevice: CachedBluetoothDevice
+
+    @Mock private lateinit var bluetoothTileDialogCallback: BluetoothTileDialogCallback
+
+    @Mock private lateinit var drawable: Drawable
+
+    @Mock private lateinit var uiEventLogger: UiEventLogger
+
+    @Mock private lateinit var logger: BluetoothTileDialogLogger
+
+    private val uiProperties =
+        BluetoothTileDialogViewModel.UiProperties.build(
+            isBluetoothEnabled = ENABLED,
+            isAutoOnToggleFeatureAvailable = ENABLED
+        )
+    @Mock private lateinit var sysuiDialogFactory: SystemUIDialog.Factory
+    @Mock private lateinit var dialogManager: SystemUIDialogManager
+    @Mock private lateinit var sysuiState: SysUiState
+    @Mock private lateinit var dialogTransitionAnimator: DialogTransitionAnimator
+
+    private val fakeSystemClock = FakeSystemClock()
+
+    private lateinit var scheduler: TestCoroutineScheduler
+    private lateinit var dispatcher: CoroutineDispatcher
+    private lateinit var testScope: TestScope
+    private lateinit var icon: Pair<Drawable, String>
+    private lateinit var mBluetoothTileDialogDelegate: BluetoothTileDialogDelegate
+    private lateinit var deviceItem: DeviceItem
+
+    @Before
+    fun setUp() {
+        scheduler = TestCoroutineScheduler()
+        dispatcher = UnconfinedTestDispatcher(scheduler)
+        testScope = TestScope(dispatcher)
+
+        whenever(sysuiState.setFlag(anyInt(), anyBoolean())).thenReturn(sysuiState)
+
+        mBluetoothTileDialogDelegate =
+            BluetoothTileDialogDelegate(
+                mContext,
+                uiProperties,
+                CONTENT_HEIGHT,
+                ENABLED,
+                bluetoothTileDialogCallback,
+                {},
+                dispatcher,
+                fakeSystemClock,
+                uiEventLogger,
+                logger,
+                sysuiDialogFactory,
+                LayoutInflater.from(mContext)
+            )
+
+        whenever(
+                sysuiDialogFactory.create(
+                    any(SystemUIDialog.Delegate::class.java),
+                    any(Context::class.java)
+                )
+            )
+            .thenAnswer {
+                SystemUIDialog(
+                    mContext,
+                    0,
+                    SystemUIDialog.DEFAULT_DISMISS_ON_DEVICE_LOCK,
+                    dialogManager,
+                    sysuiState,
+                    fakeBroadcastDispatcher,
+                    dialogTransitionAnimator,
+                    it.getArgument(0)
+                )
+            }
+
+        icon = Pair(drawable, DEVICE_NAME)
+        deviceItem =
+            DeviceItem(
+                type = DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE,
+                cachedBluetoothDevice = cachedBluetoothDevice,
+                deviceName = DEVICE_NAME,
+                connectionSummary = DEVICE_CONNECTION_SUMMARY,
+                iconWithDescription = icon,
+                background = null
+            )
+        `when`(cachedBluetoothDevice.isBusy).thenReturn(false)
+    }
+
+    @Test
+    fun testShowDialog_createRecyclerViewWithAdapter() {
+        val dialog = mBluetoothTileDialogDelegate.createDialog()
+        dialog.show()
+
+        val recyclerView = dialog.requireViewById<RecyclerView>(R.id.device_list)
+
+        assertThat(recyclerView).isNotNull()
+        assertThat(recyclerView.visibility).isEqualTo(VISIBLE)
+        assertThat(recyclerView.adapter).isNotNull()
+        assertThat(recyclerView.layoutManager is LinearLayoutManager).isTrue()
+    }
+
+    @Test
+    fun testShowDialog_displayBluetoothDevice() {
+        testScope.runTest {
+            val dialog = mBluetoothTileDialogDelegate.createDialog()
+            dialog.show()
+            fakeSystemClock.setElapsedRealtime(Long.MAX_VALUE)
+            mBluetoothTileDialogDelegate.onDeviceItemUpdated(
+                dialog,
+                listOf(deviceItem),
+                showSeeAll = false,
+                showPairNewDevice = false
+            )
+
+            val recyclerView = dialog.requireViewById<RecyclerView>(R.id.device_list)
+            val adapter = recyclerView?.adapter as BluetoothTileDialogDelegate.Adapter
+            assertThat(adapter.itemCount).isEqualTo(1)
+            assertThat(adapter.getItem(0).deviceName).isEqualTo(DEVICE_NAME)
+            assertThat(adapter.getItem(0).connectionSummary).isEqualTo(DEVICE_CONNECTION_SUMMARY)
+            assertThat(adapter.getItem(0).iconWithDescription).isEqualTo(icon)
+        }
+    }
+
+    @Test
+    fun testDeviceItemViewHolder_cachedDeviceNotBusy() {
+        deviceItem.isEnabled = true
+
+        val view =
+            LayoutInflater.from(mContext).inflate(R.layout.bluetooth_device_item, null, false)
+        val viewHolder =
+            mBluetoothTileDialogDelegate
+                .Adapter(bluetoothTileDialogCallback)
+                .DeviceItemViewHolder(view)
+        viewHolder.bind(deviceItem, bluetoothTileDialogCallback)
+        val container = view.requireViewById<View>(R.id.bluetooth_device_row)
+
+        assertThat(container).isNotNull()
+        assertThat(container.isEnabled).isTrue()
+        assertThat(container.hasOnClickListeners()).isTrue()
+    }
+
+    @Test
+    fun testDeviceItemViewHolder_cachedDeviceBusy() {
+        deviceItem.isEnabled = false
+
+        val view =
+            LayoutInflater.from(mContext).inflate(R.layout.bluetooth_device_item, null, false)
+        val viewHolder =
+            BluetoothTileDialogDelegate(
+                    mContext,
+                    uiProperties,
+                    CONTENT_HEIGHT,
+                    ENABLED,
+                    bluetoothTileDialogCallback,
+                    {},
+                    dispatcher,
+                    fakeSystemClock,
+                    uiEventLogger,
+                    logger,
+                    sysuiDialogFactory,
+                    LayoutInflater.from(mContext)
+                )
+                .Adapter(bluetoothTileDialogCallback)
+                .DeviceItemViewHolder(view)
+        viewHolder.bind(deviceItem, bluetoothTileDialogCallback)
+        val container = view.requireViewById<View>(R.id.bluetooth_device_row)
+
+        assertThat(container).isNotNull()
+        assertThat(container.isEnabled).isFalse()
+        assertThat(container.hasOnClickListeners()).isTrue()
+    }
+
+    @Test
+    fun testOnDeviceUpdated_hideSeeAll_showPairNew() {
+        testScope.runTest {
+            val dialog = mBluetoothTileDialogDelegate.createDialog()
+            dialog.show()
+            fakeSystemClock.setElapsedRealtime(Long.MAX_VALUE)
+            mBluetoothTileDialogDelegate.onDeviceItemUpdated(
+                dialog,
+                listOf(deviceItem),
+                showSeeAll = false,
+                showPairNewDevice = true
+            )
+
+            val seeAllButton = dialog.requireViewById<View>(R.id.see_all_button)
+            val pairNewButton = dialog.requireViewById<View>(R.id.pair_new_device_button)
+            val recyclerView = dialog.requireViewById<RecyclerView>(R.id.device_list)
+            val adapter = recyclerView?.adapter as BluetoothTileDialogDelegate.Adapter
+            val scrollViewContent = dialog.requireViewById<View>(R.id.scroll_view)
+
+            assertThat(seeAllButton).isNotNull()
+            assertThat(seeAllButton.visibility).isEqualTo(GONE)
+            assertThat(pairNewButton).isNotNull()
+            assertThat(pairNewButton.visibility).isEqualTo(VISIBLE)
+            assertThat(adapter.itemCount).isEqualTo(1)
+            assertThat(scrollViewContent.layoutParams.height).isEqualTo(WRAP_CONTENT)
+        }
+    }
+
+    @Test
+    fun testShowDialog_cachedHeightLargerThanMinHeight_displayFromCachedHeight() {
+        testScope.runTest {
+            val cachedHeight = Int.MAX_VALUE
+            val dialog =
+                BluetoothTileDialogDelegate(
+                        mContext,
+                        BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
+                        cachedHeight,
+                        ENABLED,
+                        bluetoothTileDialogCallback,
+                        {},
+                        dispatcher,
+                        fakeSystemClock,
+                        uiEventLogger,
+                        logger,
+                        sysuiDialogFactory,
+                        LayoutInflater.from(mContext)
+                    )
+                    .createDialog()
+            dialog.show()
+            assertThat(dialog.requireViewById<View>(R.id.scroll_view).layoutParams.height)
+                .isEqualTo(cachedHeight)
+        }
+    }
+
+    @Test
+    fun testShowDialog_cachedHeightLessThanMinHeight_displayFromUiProperties() {
+        testScope.runTest {
+            val dialog =
+                BluetoothTileDialogDelegate(
+                        mContext,
+                        BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
+                        MATCH_PARENT,
+                        ENABLED,
+                        bluetoothTileDialogCallback,
+                        {},
+                        dispatcher,
+                        fakeSystemClock,
+                        uiEventLogger,
+                        logger,
+                        sysuiDialogFactory,
+                        LayoutInflater.from(mContext)
+                    )
+                    .createDialog()
+            dialog.show()
+            assertThat(dialog.requireViewById<View>(R.id.scroll_view).layoutParams.height)
+                .isGreaterThan(MATCH_PARENT)
+        }
+    }
+
+    @Test
+    fun testShowDialog_bluetoothEnabled_autoOnToggleGone() {
+        testScope.runTest {
+            val dialog =
+                BluetoothTileDialogDelegate(
+                        mContext,
+                        BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
+                        MATCH_PARENT,
+                        ENABLED,
+                        bluetoothTileDialogCallback,
+                        {},
+                        dispatcher,
+                        fakeSystemClock,
+                        uiEventLogger,
+                        logger,
+                        sysuiDialogFactory,
+                        LayoutInflater.from(mContext)
+                    )
+                    .createDialog()
+            dialog.show()
+            assertThat(
+                    dialog.requireViewById<View>(R.id.bluetooth_auto_on_toggle_layout).visibility
+                )
+                .isEqualTo(GONE)
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogTest.kt
deleted file mode 100644
index 70b0417..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogTest.kt
+++ /dev/null
@@ -1,330 +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.qs.tiles.dialog.bluetooth
-
-import android.graphics.drawable.Drawable
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.view.LayoutInflater
-import android.view.View
-import android.view.View.GONE
-import android.view.View.VISIBLE
-import android.view.ViewGroup.LayoutParams.MATCH_PARENT
-import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
-import androidx.test.filters.SmallTest
-import com.android.internal.logging.UiEventLogger
-import com.android.settingslib.bluetooth.CachedBluetoothDevice
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.res.R
-import com.android.systemui.util.time.FakeSystemClock
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.test.TestCoroutineScheduler
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.`when`
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-class BluetoothTileDialogTest : SysuiTestCase() {
-    companion object {
-        const val DEVICE_NAME = "device"
-        const val DEVICE_CONNECTION_SUMMARY = "active"
-        const val ENABLED = true
-        const val CONTENT_HEIGHT = WRAP_CONTENT
-    }
-
-    @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
-
-    @Mock private lateinit var cachedBluetoothDevice: CachedBluetoothDevice
-
-    @Mock private lateinit var bluetoothTileDialogCallback: BluetoothTileDialogCallback
-
-    @Mock private lateinit var drawable: Drawable
-
-    @Mock private lateinit var uiEventLogger: UiEventLogger
-
-    @Mock private lateinit var logger: BluetoothTileDialogLogger
-
-    private val uiProperties =
-        BluetoothTileDialogViewModel.UiProperties.build(
-            isBluetoothEnabled = ENABLED,
-            isAutoOnToggleFeatureAvailable = ENABLED
-        )
-
-    private val fakeSystemClock = FakeSystemClock()
-
-    private lateinit var scheduler: TestCoroutineScheduler
-    private lateinit var dispatcher: CoroutineDispatcher
-    private lateinit var testScope: TestScope
-    private lateinit var icon: Pair<Drawable, String>
-    private lateinit var bluetoothTileDialog: BluetoothTileDialog
-    private lateinit var deviceItem: DeviceItem
-
-    @Before
-    fun setUp() {
-        scheduler = TestCoroutineScheduler()
-        dispatcher = UnconfinedTestDispatcher(scheduler)
-        testScope = TestScope(dispatcher)
-        bluetoothTileDialog =
-            BluetoothTileDialog(
-                ENABLED,
-                uiProperties,
-                CONTENT_HEIGHT,
-                bluetoothTileDialogCallback,
-                dispatcher,
-                fakeSystemClock,
-                uiEventLogger,
-                logger,
-                mContext
-            )
-        icon = Pair(drawable, DEVICE_NAME)
-        deviceItem =
-            DeviceItem(
-                type = DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE,
-                cachedBluetoothDevice = cachedBluetoothDevice,
-                deviceName = DEVICE_NAME,
-                connectionSummary = DEVICE_CONNECTION_SUMMARY,
-                iconWithDescription = icon,
-                background = null
-            )
-        `when`(cachedBluetoothDevice.isBusy).thenReturn(false)
-    }
-
-    @Test
-    fun testShowDialog_createRecyclerViewWithAdapter() {
-        bluetoothTileDialog.show()
-
-        val recyclerView = bluetoothTileDialog.requireViewById<RecyclerView>(R.id.device_list)
-
-        assertThat(bluetoothTileDialog.isShowing).isTrue()
-        assertThat(recyclerView).isNotNull()
-        assertThat(recyclerView.visibility).isEqualTo(VISIBLE)
-        assertThat(recyclerView.adapter).isNotNull()
-        assertThat(recyclerView.layoutManager is LinearLayoutManager).isTrue()
-    }
-
-    @Test
-    fun testShowDialog_displayBluetoothDevice() {
-        testScope.runTest {
-            bluetoothTileDialog =
-                BluetoothTileDialog(
-                    ENABLED,
-                    uiProperties,
-                    CONTENT_HEIGHT,
-                    bluetoothTileDialogCallback,
-                    dispatcher,
-                    fakeSystemClock,
-                    uiEventLogger,
-                    logger,
-                    mContext
-                )
-            bluetoothTileDialog.show()
-            fakeSystemClock.setElapsedRealtime(Long.MAX_VALUE)
-            bluetoothTileDialog.onDeviceItemUpdated(
-                listOf(deviceItem),
-                showSeeAll = false,
-                showPairNewDevice = false
-            )
-
-            val recyclerView = bluetoothTileDialog.requireViewById<RecyclerView>(R.id.device_list)
-            val adapter = recyclerView.adapter as BluetoothTileDialog.Adapter
-            assertThat(adapter.itemCount).isEqualTo(1)
-            assertThat(adapter.getItem(0).deviceName).isEqualTo(DEVICE_NAME)
-            assertThat(adapter.getItem(0).connectionSummary).isEqualTo(DEVICE_CONNECTION_SUMMARY)
-            assertThat(adapter.getItem(0).iconWithDescription).isEqualTo(icon)
-        }
-    }
-
-    @Test
-    fun testDeviceItemViewHolder_cachedDeviceNotBusy() {
-        deviceItem.isEnabled = true
-
-        val view =
-            LayoutInflater.from(mContext).inflate(R.layout.bluetooth_device_item, null, false)
-        val viewHolder =
-            BluetoothTileDialog(
-                    ENABLED,
-                    uiProperties,
-                    CONTENT_HEIGHT,
-                    bluetoothTileDialogCallback,
-                    dispatcher,
-                    fakeSystemClock,
-                    uiEventLogger,
-                    logger,
-                    mContext
-                )
-                .Adapter(bluetoothTileDialogCallback)
-                .DeviceItemViewHolder(view)
-        viewHolder.bind(deviceItem, bluetoothTileDialogCallback)
-        val container = view.requireViewById<View>(R.id.bluetooth_device_row)
-
-        assertThat(container).isNotNull()
-        assertThat(container.isEnabled).isTrue()
-        assertThat(container.hasOnClickListeners()).isTrue()
-    }
-
-    @Test
-    fun testDeviceItemViewHolder_cachedDeviceBusy() {
-        deviceItem.isEnabled = false
-
-        val view =
-            LayoutInflater.from(mContext).inflate(R.layout.bluetooth_device_item, null, false)
-        val viewHolder =
-            BluetoothTileDialog(
-                    ENABLED,
-                    uiProperties,
-                    CONTENT_HEIGHT,
-                    bluetoothTileDialogCallback,
-                    dispatcher,
-                    fakeSystemClock,
-                    uiEventLogger,
-                    logger,
-                    mContext
-                )
-                .Adapter(bluetoothTileDialogCallback)
-                .DeviceItemViewHolder(view)
-        viewHolder.bind(deviceItem, bluetoothTileDialogCallback)
-        val container = view.requireViewById<View>(R.id.bluetooth_device_row)
-
-        assertThat(container).isNotNull()
-        assertThat(container.isEnabled).isFalse()
-        assertThat(container.hasOnClickListeners()).isTrue()
-    }
-
-    @Test
-    fun testOnDeviceUpdated_hideSeeAll_showPairNew() {
-        testScope.runTest {
-            bluetoothTileDialog =
-                BluetoothTileDialog(
-                    ENABLED,
-                    uiProperties,
-                    CONTENT_HEIGHT,
-                    bluetoothTileDialogCallback,
-                    dispatcher,
-                    fakeSystemClock,
-                    uiEventLogger,
-                    logger,
-                    mContext
-                )
-            bluetoothTileDialog.show()
-            fakeSystemClock.setElapsedRealtime(Long.MAX_VALUE)
-            bluetoothTileDialog.onDeviceItemUpdated(
-                listOf(deviceItem),
-                showSeeAll = false,
-                showPairNewDevice = true
-            )
-
-            val seeAllButton = bluetoothTileDialog.requireViewById<View>(R.id.see_all_button)
-            val pairNewButton =
-                bluetoothTileDialog.requireViewById<View>(R.id.pair_new_device_button)
-            val recyclerView = bluetoothTileDialog.requireViewById<RecyclerView>(R.id.device_list)
-            val adapter = recyclerView.adapter as BluetoothTileDialog.Adapter
-            val scrollViewContent = bluetoothTileDialog.requireViewById<View>(R.id.scroll_view)
-
-            assertThat(seeAllButton).isNotNull()
-            assertThat(seeAllButton.visibility).isEqualTo(GONE)
-            assertThat(pairNewButton).isNotNull()
-            assertThat(pairNewButton.visibility).isEqualTo(VISIBLE)
-            assertThat(adapter.itemCount).isEqualTo(1)
-            assertThat(scrollViewContent.layoutParams.height).isEqualTo(WRAP_CONTENT)
-        }
-    }
-
-    @Test
-    fun testShowDialog_cachedHeightLargerThanMinHeight_displayFromCachedHeight() {
-        testScope.runTest {
-            val cachedHeight = Int.MAX_VALUE
-            bluetoothTileDialog =
-                BluetoothTileDialog(
-                    ENABLED,
-                    uiProperties,
-                    cachedHeight,
-                    bluetoothTileDialogCallback,
-                    dispatcher,
-                    fakeSystemClock,
-                    uiEventLogger,
-                    logger,
-                    mContext
-                )
-            bluetoothTileDialog.show()
-            assertThat(
-                    bluetoothTileDialog.requireViewById<View>(R.id.scroll_view).layoutParams.height
-                )
-                .isEqualTo(cachedHeight)
-        }
-    }
-
-    @Test
-    fun testShowDialog_cachedHeightLessThanMinHeight_displayFromUiProperties() {
-        testScope.runTest {
-            bluetoothTileDialog =
-                BluetoothTileDialog(
-                    ENABLED,
-                    uiProperties,
-                    MATCH_PARENT,
-                    bluetoothTileDialogCallback,
-                    dispatcher,
-                    fakeSystemClock,
-                    uiEventLogger,
-                    logger,
-                    mContext
-                )
-            bluetoothTileDialog.show()
-            assertThat(
-                    bluetoothTileDialog.requireViewById<View>(R.id.scroll_view).layoutParams.height
-                )
-                .isGreaterThan(MATCH_PARENT)
-        }
-    }
-
-    @Test
-    fun testShowDialog_bluetoothEnabled_autoOnToggleGone() {
-        testScope.runTest {
-            bluetoothTileDialog =
-                BluetoothTileDialog(
-                    ENABLED,
-                    BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
-                    MATCH_PARENT,
-                    bluetoothTileDialogCallback,
-                    dispatcher,
-                    fakeSystemClock,
-                    uiEventLogger,
-                    logger,
-                    mContext
-                )
-            bluetoothTileDialog.show()
-            assertThat(
-                    bluetoothTileDialog
-                        .requireViewById<View>(R.id.bluetooth_auto_on_toggle_layout)
-                        .visibility
-                )
-                .isEqualTo(GONE)
-        }
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
index cb9f4b4..39e2413 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.qs.tiles.dialog.bluetooth
 
-import android.content.SharedPreferences
 import android.content.pm.UserInfo
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
@@ -31,10 +30,14 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.DialogTransitionAnimator
 import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.phone.SystemUIDialog
 import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.util.FakeSharedPreferences
 import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.kotlin.getMutableStateFlow
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.nullable
+import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.settings.FakeSettings
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
@@ -50,12 +53,12 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
 import org.mockito.Mockito.anyBoolean
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
 import org.mockito.junit.MockitoJUnit
 import org.mockito.junit.MockitoRule
 
@@ -84,9 +87,15 @@
 
     @Mock private lateinit var uiEventLogger: UiEventLogger
 
-    @Mock private lateinit var logger: BluetoothTileDialogLogger
+    @Mock
+    private lateinit var mBluetoothTileDialogDelegateDelegateFactory:
+        BluetoothTileDialogDelegate.Factory
 
-    @Mock private lateinit var sharedPreferences: SharedPreferences
+    @Mock private lateinit var bluetoothTileDialogDelegate: BluetoothTileDialogDelegate
+
+    @Mock private lateinit var sysuiDialog: SystemUIDialog
+
+    private val sharedPreferences = FakeSharedPreferences()
 
     private lateinit var scheduler: TestCoroutineScheduler
     private lateinit var dispatcher: CoroutineDispatcher
@@ -123,20 +132,38 @@
                 ),
                 mDialogTransitionAnimator,
                 activityStarter,
-                fakeSystemClock,
                 uiEventLogger,
-                logger,
                 testScope.backgroundScope,
                 dispatcher,
                 dispatcher,
                 sharedPreferences,
+                mBluetoothTileDialogDelegateDelegateFactory
             )
-        `when`(deviceItemInteractor.deviceItemUpdate).thenReturn(MutableSharedFlow())
-        `when`(bluetoothStateInteractor.bluetoothStateUpdate)
+        whenever(deviceItemInteractor.deviceItemUpdate).thenReturn(MutableSharedFlow())
+        whenever(bluetoothStateInteractor.bluetoothStateUpdate)
             .thenReturn(MutableStateFlow(null).asStateFlow())
-        `when`(deviceItemInteractor.deviceItemUpdateRequest)
+        whenever(deviceItemInteractor.deviceItemUpdateRequest)
             .thenReturn(MutableStateFlow(Unit).asStateFlow())
-        `when`(bluetoothStateInteractor.isBluetoothEnabled).thenReturn(true)
+        whenever(bluetoothStateInteractor.isBluetoothEnabled).thenReturn(true)
+        whenever(
+                mBluetoothTileDialogDelegateDelegateFactory.create(
+                    any(),
+                    any(),
+                    anyInt(),
+                    ArgumentMatchers.anyBoolean(),
+                    any(),
+                    any()
+                )
+            )
+            .thenReturn(bluetoothTileDialogDelegate)
+        whenever(bluetoothTileDialogDelegate.createDialog()).thenReturn(sysuiDialog)
+        whenever(bluetoothTileDialogDelegate.bluetoothStateToggle)
+            .thenReturn(getMutableStateFlow(false))
+        whenever(bluetoothTileDialogDelegate.deviceItemClick)
+            .thenReturn(getMutableStateFlow(deviceItem))
+        whenever(bluetoothTileDialogDelegate.contentHeight).thenReturn(getMutableStateFlow(0))
+        whenever(bluetoothTileDialogDelegate.bluetoothAutoOnToggle)
+            .thenReturn(getMutableStateFlow(false))
     }
 
     @Test
@@ -145,7 +172,6 @@
             bluetoothTileDialogViewModel.showDialog(context, null)
 
             verify(mDialogTransitionAnimator, never()).showFromView(any(), any(), any(), any())
-            verify(uiEventLogger).log(BluetoothTileDialogUiEvent.BLUETOOTH_TILE_DIALOG_SHOWN)
         }
     }
 
@@ -191,7 +217,7 @@
     @Test
     fun testStartSettingsActivity_activityLaunched_dialogDismissed() {
         testScope.runTest {
-            `when`(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice)
+            whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice)
             bluetoothTileDialogViewModel.showDialog(context, null)
 
             val clickedView = View(context)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactoryTest.kt
index 92c7326..a8cd8c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactoryTest.kt
@@ -16,10 +16,18 @@
 
 package com.android.systemui.qs.tiles.dialog.bluetooth
 
+import android.bluetooth.BluetoothDevice
+import android.content.pm.PackageInfo
+import android.content.pm.PackageManager
+import android.media.AudioManager
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.BluetoothUtils
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.flags.Flags
 import com.android.systemui.SysuiTestCase
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
@@ -35,19 +43,26 @@
 @RunWith(AndroidTestingRunner::class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 class DeviceItemFactoryTest : SysuiTestCase() {
-
     @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
 
     @Mock private lateinit var cachedDevice: CachedBluetoothDevice
+    @Mock private lateinit var bluetoothDevice: BluetoothDevice
+    @Mock private lateinit var packageManager: PackageManager
 
     private val availableMediaDeviceItemFactory = AvailableMediaDeviceItemFactory()
     private val connectedDeviceItemFactory = ConnectedDeviceItemFactory()
     private val savedDeviceItemFactory = SavedDeviceItemFactory()
 
+    private val audioManager = context.getSystemService(AudioManager::class.java)!!
+
     @Before
     fun setup() {
         `when`(cachedDevice.name).thenReturn(DEVICE_NAME)
+        `when`(cachedDevice.address).thenReturn(DEVICE_ADDRESS)
+        `when`(cachedDevice.device).thenReturn(bluetoothDevice)
         `when`(cachedDevice.connectionSummary).thenReturn(CONNECTION_SUMMARY)
+
+        context.setMockPackageManager(packageManager)
     }
 
     @Test
@@ -72,6 +87,225 @@
         assertThat(deviceItem.background).isNotNull()
     }
 
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_bondedAndNotConnected_returnsTrue() {
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(cachedDevice.isConnected).thenReturn(false)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isTrue()
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_connected_returnsFalse() {
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(cachedDevice.isConnected).thenReturn(true)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_notBonded_returnsFalse() {
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
+        `when`(cachedDevice.isConnected).thenReturn(false)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_exclusivelyManaged_returnsFalse() {
+        val exclusiveManagerName =
+            BluetoothUtils.getExclusiveManagers().firstOrNull() ?: FAKE_EXCLUSIVE_MANAGER_NAME
+        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
+            .thenReturn(exclusiveManagerName.toByteArray())
+        `when`(packageManager.getPackageInfo(exclusiveManagerName, 0)).thenReturn(PackageInfo())
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(cachedDevice.isConnected).thenReturn(false)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_noExclusiveManager_returnsTrue() {
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(cachedDevice.isConnected).thenReturn(false)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isTrue()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_notAllowedExclusiveManager_returnsTrue() {
+        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
+            .thenReturn(FAKE_EXCLUSIVE_MANAGER_NAME.toByteArray())
+        `when`(packageManager.getPackageInfo(FAKE_EXCLUSIVE_MANAGER_NAME, 0))
+            .thenReturn(PackageInfo())
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(cachedDevice.isConnected).thenReturn(false)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isTrue()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_uninstalledExclusiveManager_returnsTrue() {
+        val exclusiveManagerName =
+            BluetoothUtils.getExclusiveManagers().firstOrNull() ?: FAKE_EXCLUSIVE_MANAGER_NAME
+        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
+            .thenReturn(exclusiveManagerName.toByteArray())
+        `when`(packageManager.getPackageInfo(exclusiveManagerName, 0))
+            .thenThrow(PackageManager.NameNotFoundException("Test!"))
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(cachedDevice.isConnected).thenReturn(false)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isTrue()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_notExclusivelyManaged_notBonded_returnsFalse() {
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
+        `when`(cachedDevice.isConnected).thenReturn(false)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_notExclusivelyManaged_connected_returnsFalse() {
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(cachedDevice.isConnected).thenReturn(true)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_bondedAndConnected_returnsTrue() {
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(bluetoothDevice.isConnected).thenReturn(true)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isTrue()
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_notConnected_returnsFalse() {
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(bluetoothDevice.isConnected).thenReturn(false)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_notBonded_returnsFalse() {
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
+        `when`(bluetoothDevice.isConnected).thenReturn(true)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_exclusivelyManaged_returnsFalse() {
+        val exclusiveManagerName =
+            BluetoothUtils.getExclusiveManagers().firstOrNull() ?: FAKE_EXCLUSIVE_MANAGER_NAME
+        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
+            .thenReturn(exclusiveManagerName.toByteArray())
+        `when`(packageManager.getPackageInfo(exclusiveManagerName, 0)).thenReturn(PackageInfo())
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(bluetoothDevice.isConnected).thenReturn(true)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_noExclusiveManager_returnsTrue() {
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(bluetoothDevice.isConnected).thenReturn(true)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isTrue()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_notAllowedExclusiveManager_returnsTrue() {
+        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
+            .thenReturn(FAKE_EXCLUSIVE_MANAGER_NAME.toByteArray())
+        `when`(packageManager.getPackageInfo(FAKE_EXCLUSIVE_MANAGER_NAME, 0))
+            .thenReturn(PackageInfo())
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(bluetoothDevice.isConnected).thenReturn(true)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isTrue()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_uninstalledExclusiveManager_returnsTrue() {
+        val exclusiveManagerName =
+            BluetoothUtils.getExclusiveManagers().firstOrNull() ?: FAKE_EXCLUSIVE_MANAGER_NAME
+        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
+            .thenReturn(exclusiveManagerName.toByteArray())
+        `when`(packageManager.getPackageInfo(exclusiveManagerName, 0))
+            .thenThrow(PackageManager.NameNotFoundException("Test!"))
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(bluetoothDevice.isConnected).thenReturn(true)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isTrue()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_notExclusivelyManaged_notBonded_returnsFalse() {
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
+        `when`(bluetoothDevice.isConnected).thenReturn(true)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_notExclusivelyManaged_notConnected_returnsFalse() {
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(bluetoothDevice.isConnected).thenReturn(false)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
     private fun assertDeviceItem(deviceItem: DeviceItem?, deviceItemType: DeviceItemType) {
         assertThat(deviceItem).isNotNull()
         assertThat(deviceItem!!.type).isEqualTo(deviceItemType)
@@ -83,5 +317,7 @@
     companion object {
         const val DEVICE_NAME = "DeviceName"
         const val CONNECTION_SUMMARY = "ConnectionSummary"
+        private const val FAKE_EXCLUSIVE_MANAGER_NAME = "com.fake.name"
+        private const val DEVICE_ADDRESS = "04:52:C7:0B:D8:3C"
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractorTest.kt
index e236f4a..ddf0b9a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractorTest.kt
@@ -279,6 +279,7 @@
     ): DeviceItemFactory {
         return object : DeviceItemFactory() {
             override fun isFilterMatched(
+                context: Context,
                 cachedDevice: CachedBluetoothDevice,
                 audioManager: AudioManager?
             ) = isFilterMatchFunc(cachedDevice)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/SaveImageInBackgroundTaskTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/SaveImageInBackgroundTaskTest.kt
index fbb77cd..25dd9fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/SaveImageInBackgroundTaskTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/SaveImageInBackgroundTaskTest.kt
@@ -34,7 +34,6 @@
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import java.util.concurrent.CompletableFuture
-import java.util.function.Supplier
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertNull
 import org.junit.Before
@@ -46,8 +45,6 @@
     private val smartActions = mock<ScreenshotSmartActions>()
     private val smartActionsProvider = mock<ScreenshotNotificationSmartActionsProvider>()
     private val saveImageData = SaveImageInBackgroundData()
-    private val sharedTransitionSupplier =
-        mock<Supplier<ScreenshotController.SavedImageData.ActionTransition>>()
     private val testScreenshotId: String = "testScreenshotId"
     private val testBitmap = mock<Bitmap>()
     private val testUser = UserHandle.getUserHandleForUid(0)
@@ -88,7 +85,6 @@
             imageExporter,
             smartActions,
             saveImageData,
-            sharedTransitionSupplier,
             smartActionsProvider,
         )
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
index 85c8ba7..2a9aca7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
@@ -20,8 +20,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.Mockito.doThrow;
@@ -32,19 +30,15 @@
 import static org.mockito.Mockito.when;
 
 import android.app.Notification;
-import android.content.Intent;
 import android.graphics.Bitmap;
 import android.net.Uri;
-import android.os.Bundle;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.UserHandle;
 import android.testing.AndroidTestingRunner;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -84,7 +78,7 @@
         ScreenshotNotificationSmartActionsProvider smartActionsProvider = mock(
                 ScreenshotNotificationSmartActionsProvider.class);
         when(smartActionsProvider.getActions(any(), any(), any(), any(), any(), any()))
-            .thenThrow(RuntimeException.class);
+                .thenThrow(RuntimeException.class);
         CompletableFuture<List<Notification.Action>> smartActionsFuture =
                 mScreenshotSmartActions.getSmartActionsFuture(
                         "", Uri.parse("content://authority/data"), bitmap, smartActionsProvider,
@@ -166,89 +160,4 @@
         List<Notification.Action> smartActions = smartActionsFuture.get(5, TimeUnit.MILLISECONDS);
         assertEquals(smartActions.size(), 0);
     }
-
-    // Tests for share action extras
-    @Test
-    public void testShareActionExtras() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-
-        ScreenshotController.SaveImageInBackgroundData
-                data = new ScreenshotController.SaveImageInBackgroundData();
-        data.image = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
-        data.finisher = null;
-        data.mActionsReadyListener = null;
-        SaveImageInBackgroundTask task =
-                new SaveImageInBackgroundTask(mContext, null, null, mScreenshotSmartActions, data,
-                        ActionTransition::new, mSmartActionsProvider);
-
-        Notification.Action shareAction = task.createShareAction(mContext, mContext.getResources(),
-                Uri.parse("Screenshot_123.png"), true).get().action;
-
-        Intent intent = shareAction.actionIntent.getIntent();
-        assertNotNull(intent);
-        Bundle bundle = intent.getExtras();
-        assertTrue(bundle.containsKey(ScreenshotController.EXTRA_ID));
-        assertTrue(bundle.containsKey(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED));
-        assertEquals(ScreenshotController.ACTION_TYPE_SHARE, shareAction.title);
-        assertEquals(Intent.ACTION_SEND, intent.getAction());
-    }
-
-    // Tests for edit action extras
-    @Test
-    public void testEditActionExtras() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-
-        ScreenshotController.SaveImageInBackgroundData
-                data = new ScreenshotController.SaveImageInBackgroundData();
-        data.image = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
-        data.finisher = null;
-        data.mActionsReadyListener = null;
-        SaveImageInBackgroundTask task =
-                new SaveImageInBackgroundTask(mContext, null, null, mScreenshotSmartActions, data,
-                        ActionTransition::new, mSmartActionsProvider);
-
-        Notification.Action editAction = task.createEditAction(mContext, mContext.getResources(),
-                Uri.parse("Screenshot_123.png"), true).get().action;
-
-        Intent intent = editAction.actionIntent.getIntent();
-        assertNotNull(intent);
-        Bundle bundle = intent.getExtras();
-        assertTrue(bundle.containsKey(ScreenshotController.EXTRA_ID));
-        assertTrue(bundle.containsKey(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED));
-        assertEquals(ScreenshotController.ACTION_TYPE_EDIT, editAction.title);
-        assertEquals(Intent.ACTION_EDIT, intent.getAction());
-    }
-
-    // Tests for share action extras
-    @Test
-    public void testDeleteActionExtras() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-
-        ScreenshotController.SaveImageInBackgroundData
-                data = new ScreenshotController.SaveImageInBackgroundData();
-        data.image = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
-        data.finisher = null;
-        data.mActionsReadyListener = null;
-        SaveImageInBackgroundTask task =
-                new SaveImageInBackgroundTask(mContext, null, null, mScreenshotSmartActions, data,
-                        ActionTransition::new, mSmartActionsProvider);
-
-        Notification.Action deleteAction = task.createDeleteAction(mContext,
-                mContext.getResources(),
-                Uri.parse("Screenshot_123.png"), true);
-
-        Intent intent = deleteAction.actionIntent.getIntent();
-        assertNotNull(intent);
-        Bundle bundle = intent.getExtras();
-        assertTrue(bundle.containsKey(ScreenshotController.EXTRA_ID));
-        assertTrue(bundle.containsKey(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED));
-        assertEquals(deleteAction.title, ScreenshotController.ACTION_TYPE_DELETE);
-        assertNull(intent.getAction());
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
index b94e483..31acd86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
@@ -23,6 +23,7 @@
 import android.view.View
 import android.view.ViewGroup
 import android.view.WindowManagerPolicyConstants.EXTRA_FROM_BRIGHTNESS_KEY
+import androidx.test.filters.FlakyTest
 import androidx.test.filters.SmallTest
 import androidx.test.rule.ActivityTestRule
 import com.android.systemui.SysuiTestCase
@@ -183,6 +184,7 @@
     }
 
     @OptIn(FlowPreview::class)
+    @FlakyTest(bugId = 326186573)
     @Test
     fun testFinishOnQSExpanded() = runTest {
         val isQSExpanded = MutableStateFlow(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
index 665fc75..62d2d0e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
@@ -26,6 +26,7 @@
 import android.view.WindowManager
 import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.data.repository.FakeCommunalRepository
@@ -33,9 +34,8 @@
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.domain.interactor.communalInteractor
 import com.android.systemui.communal.domain.interactor.setCommunalAvailable
-import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
-import com.android.systemui.compose.ComposeFacade
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testDispatcher
@@ -52,9 +52,7 @@
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import org.junit.After
 import org.junit.Assert.assertThrows
-import org.junit.Assume.assumeTrue
 import org.junit.Before
-import org.junit.BeforeClass
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
@@ -155,7 +153,7 @@
     @Test
     fun onTouchEvent_communalClosed_doesNotIntercept() {
         // Communal is closed.
-        goToScene(CommunalSceneKey.Blank)
+        goToScene(CommunalScenes.Blank)
 
         assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
     }
@@ -163,7 +161,7 @@
     @Test
     fun onTouchEvent_openGesture_interceptsTouches() {
         // Communal is closed.
-        goToScene(CommunalSceneKey.Blank)
+        goToScene(CommunalScenes.Blank)
 
         // Initial touch down is intercepted, and so are touches outside of the region, until an
         // up event is received.
@@ -176,7 +174,7 @@
     @Test
     fun onTouchEvent_communalOpen_interceptsTouches() {
         // Communal is open.
-        goToScene(CommunalSceneKey.Communal)
+        goToScene(CommunalScenes.Communal)
 
         // Touch events are intercepted outside of any gesture areas.
         assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
@@ -187,7 +185,7 @@
     @Test
     fun onTouchEvent_topSwipeWhenCommunalOpen_doesNotIntercept() {
         // Communal is open.
-        goToScene(CommunalSceneKey.Communal)
+        goToScene(CommunalScenes.Communal)
 
         // Touch event in the top swipe reqgion is not intercepted.
         assertThat(underTest.onTouchEvent(DOWN_IN_TOP_SWIPE_REGION_EVENT)).isFalse()
@@ -196,7 +194,7 @@
     @Test
     fun onTouchEvent_bottomSwipeWhenCommunalOpen_doesNotIntercept() {
         // Communal is open.
-        goToScene(CommunalSceneKey.Communal)
+        goToScene(CommunalScenes.Communal)
 
         // Touch event in the bottom swipe reqgion is not intercepted.
         assertThat(underTest.onTouchEvent(DOWN_IN_BOTTOM_SWIPE_REGION_EVENT)).isFalse()
@@ -205,7 +203,7 @@
     @Test
     fun onTouchEvent_communalAndBouncerShowing_doesNotIntercept() {
         // Communal is open.
-        goToScene(CommunalSceneKey.Communal)
+        goToScene(CommunalScenes.Communal)
 
         // Bouncer is visible.
         bouncerShowingFlow.value = true
@@ -220,7 +218,7 @@
     @Test
     fun onTouchEvent_communalAndShadeShowing_doesNotIntercept() {
         // Communal is open.
-        goToScene(CommunalSceneKey.Communal)
+        goToScene(CommunalScenes.Communal)
 
         shadeShowingFlow.value = true
         testableLooper.processAllMessages()
@@ -232,7 +230,7 @@
     @Test
     fun onTouchEvent_containerViewDisposed_doesNotIntercept() {
         // Communal is open.
-        goToScene(CommunalSceneKey.Communal)
+        goToScene(CommunalScenes.Communal)
 
         // Touch events are intercepted.
         assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
@@ -265,7 +263,7 @@
         wm.updateViewLayout(parentView, lp)
     }
 
-    private fun goToScene(scene: CommunalSceneKey) {
+    private fun goToScene(scene: SceneKey) {
         communalRepository.setDesiredScene(scene)
         testableLooper.processAllMessages()
     }
@@ -305,13 +303,5 @@
             MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, CONTAINER_HEIGHT.toFloat(), 0)
         private val MOVE_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
         private val UP_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0)
-
-        @BeforeClass
-        @JvmStatic
-        fun beforeClass() {
-            // Glanceable hub requires Compose, no point running any of these tests if compose isn't
-            // enabled.
-            assumeTrue(ComposeFacade.isComposeAvailable())
-        }
     }
 }
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 950a9db..fd7b139 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -599,6 +599,8 @@
         // Primary Bouncer->Gone
         when(mPrimaryBouncerToGoneTransitionViewModel.getLockscreenAlpha())
                 .thenReturn(emptyFlow());
+        when(mPrimaryBouncerToGoneTransitionViewModel.getNotificationAlpha())
+                .thenReturn(emptyFlow());
 
         NotificationsKeyguardViewStateRepository notifsKeyguardViewStateRepository =
                 new NotificationsKeyguardViewStateRepository();
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 b426d1d..960fd59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.shade
 
+import org.mockito.Mockito.`when` as whenever
 import android.content.Context
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
@@ -33,7 +34,6 @@
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.bouncer.ui.binder.BouncerViewBinder
 import com.android.systemui.classifier.FalsingCollectorFake
-import com.android.systemui.compose.ComposeFacade.isComposeAvailable
 import com.android.systemui.dock.DockManager
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FakeFeatureFlagsClassic
@@ -88,7 +88,6 @@
 import org.mockito.Mockito.never
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -511,10 +510,6 @@
     @Test
     @Ignore("b/321332798")
     fun setsUpCommunalHubLayout_whenFlagEnabled() {
-        if (!isComposeAvailable()) {
-            return
-        }
-
         whenever(mGlanceableHubContainerController.communalAvailable())
             .thenReturn(MutableStateFlow(true))
 
@@ -537,10 +532,6 @@
 
     @Test
     fun doesNotSetupCommunalHubLayout_whenFlagDisabled() {
-        if (!isComposeAvailable()) {
-            return
-        }
-
         whenever(mGlanceableHubContainerController.communalAvailable())
             .thenReturn(MutableStateFlow(false))
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt
index 7737b43..2f957b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt
@@ -1,15 +1,47 @@
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
 package com.android.systemui.shade.transition
 
+import android.platform.test.annotations.DisableFlags
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
+import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
+import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
+import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.domain.interactor.PanelExpansionInteractor
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.FakeSceneDataSource
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.shared.model.fakeSceneDataSource
 import com.android.systemui.shade.STATE_OPENING
 import com.android.systemui.shade.ShadeExpansionChangeEvent
 import com.android.systemui.shade.ShadeExpansionStateManager
 import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.panelExpansionInteractor
 import com.android.systemui.statusbar.policy.FakeConfigurationController
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -29,32 +61,95 @@
 
     private val configurationController = FakeConfigurationController()
     private val shadeExpansionStateManager = ShadeExpansionStateManager()
+    private val kosmos = testKosmos()
+    private lateinit var testScope: TestScope
+    private lateinit var applicationScope: CoroutineScope
+    private lateinit var panelExpansionInteractor: PanelExpansionInteractor
+    private lateinit var deviceEntryRepository: FakeDeviceEntryRepository
+    private lateinit var deviceUnlockedInteractor: DeviceUnlockedInteractor
+    private lateinit var sceneInteractor: SceneInteractor
+    private lateinit var fakeSceneDataSource: FakeSceneDataSource
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
+        testScope = kosmos.testScope
+        applicationScope = kosmos.applicationCoroutineScope
+        panelExpansionInteractor = kosmos.panelExpansionInteractor
+        deviceEntryRepository = kosmos.fakeDeviceEntryRepository
+        deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor
+        sceneInteractor = kosmos.sceneInteractor
+        fakeSceneDataSource = kosmos.fakeSceneDataSource
+
         controller =
             ShadeTransitionController(
+                applicationScope,
                 configurationController,
                 shadeExpansionStateManager,
                 dumpManager,
                 context,
                 scrimShadeTransitionController,
                 statusBarStateController,
-                    ResourcesSplitShadeStateController()
-            )
+                ResourcesSplitShadeStateController(),
+            ) {
+                panelExpansionInteractor
+            }
     }
 
     @Test
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     fun onPanelStateChanged_forwardsToScrimTransitionController() {
-        startPanelExpansion()
+        startLegacyPanelExpansion()
 
         verify(scrimShadeTransitionController).onPanelStateChanged(STATE_OPENING)
         verify(scrimShadeTransitionController).onPanelExpansionChanged(DEFAULT_EXPANSION_EVENT)
     }
 
-    private fun startPanelExpansion() {
+    @Test
+    @EnableSceneContainer
+    fun sceneChanges_forwardsToScrimTransitionController() =
+        testScope.runTest {
+            var latestChangeEvent: ShadeExpansionChangeEvent? = null
+            whenever(scrimShadeTransitionController.onPanelExpansionChanged(any())).thenAnswer {
+                latestChangeEvent = it.arguments[0] as ShadeExpansionChangeEvent
+                Unit
+            }
+            setUnlocked(true)
+            val transitionState =
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(Scenes.Gone)
+                )
+            sceneInteractor.setTransitionState(transitionState)
+
+            changeScene(Scenes.Gone, transitionState)
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
+
+            assertThat(latestChangeEvent)
+                .isEqualTo(
+                    ShadeExpansionChangeEvent(
+                        fraction = 0f,
+                        expanded = false,
+                        tracking = true,
+                        dragDownPxAmount = 0f,
+                    )
+                )
+
+            changeScene(Scenes.Shade, transitionState) { progress ->
+                assertThat(latestChangeEvent)
+                    .isEqualTo(
+                        ShadeExpansionChangeEvent(
+                            fraction = progress,
+                            expanded = progress > 0,
+                            tracking = true,
+                            dragDownPxAmount = 0f,
+                        )
+                    )
+            }
+        }
+
+    private fun startLegacyPanelExpansion() {
         shadeExpansionStateManager.onPanelExpansionChanged(
             DEFAULT_EXPANSION_EVENT.fraction,
             DEFAULT_EXPANSION_EVENT.expanded,
@@ -63,6 +158,52 @@
         )
     }
 
+    private fun TestScope.setUnlocked(isUnlocked: Boolean) {
+        val isDeviceUnlocked by collectLastValue(deviceUnlockedInteractor.isDeviceUnlocked)
+        deviceEntryRepository.setUnlocked(isUnlocked)
+        runCurrent()
+
+        assertThat(isDeviceUnlocked).isEqualTo(isUnlocked)
+    }
+
+    private fun TestScope.changeScene(
+        toScene: SceneKey,
+        transitionState: MutableStateFlow<ObservableTransitionState>,
+        assertDuringProgress: ((progress: Float) -> Unit) = {},
+    ) {
+        val currentScene by collectLastValue(sceneInteractor.currentScene)
+        val progressFlow = MutableStateFlow(0f)
+        transitionState.value =
+            ObservableTransitionState.Transition(
+                fromScene = checkNotNull(currentScene),
+                toScene = toScene,
+                progress = progressFlow,
+                isInitiatedByUserInput = true,
+                isUserInputOngoing = flowOf(true),
+            )
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        progressFlow.value = 0.2f
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        progressFlow.value = 0.6f
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        progressFlow.value = 1f
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        transitionState.value = ObservableTransitionState.Idle(toScene)
+        fakeSceneDataSource.changeScene(toScene)
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        assertThat(currentScene).isEqualTo(toScene)
+    }
+
     companion object {
         private const val DEFAULT_DRAG_DOWN_AMOUNT = 123f
         private val DEFAULT_EXPANSION_EVENT =
@@ -70,6 +211,7 @@
                 fraction = 0.5f,
                 expanded = true,
                 tracking = true,
-                dragDownPxAmount = DEFAULT_DRAG_DOWN_AMOUNT)
+                dragDownPxAmount = DEFAULT_DRAG_DOWN_AMOUNT
+            )
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java
index 460892a..660e8da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java
@@ -49,6 +49,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.RemoteAnimationTargetCompat;
 import com.android.wm.shell.shared.TransitionUtil;
 
 import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index aa53558..1504d4c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -92,6 +92,21 @@
 @TestableLooper.RunWithLooper
 public class KeyguardIndicationControllerTest extends KeyguardIndicationControllerBaseTest {
     @Test
+    public void afterFaceLockout_skipShowingFaceNotRecognized() {
+        createController();
+        onFaceLockoutError("lockout");
+        verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE, "lockout");
+        clearInvocations(mRotateTextViewController);
+
+        // WHEN face sends an onBiometricHelp BIOMETRIC_HELP_FACE_NOT_RECOGNIZED (face fail)
+        mKeyguardUpdateMonitorCallback.onBiometricHelp(
+                BIOMETRIC_HELP_FACE_NOT_RECOGNIZED,
+                "Face not recognized",
+                BiometricSourceType.FACE);
+        verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE); // no updated message
+    }
+
+    @Test
     public void createController_setIndicationAreaAgain_destroysPreviousRotateTextViewController() {
         // GIVEN a controller with a mocked rotate text view controlller
         final KeyguardIndicationRotateTextViewController mockedRotateTextViewController =
@@ -593,7 +608,7 @@
         mController.getKeyguardCallback().onBiometricError(FACE_ERROR_TIMEOUT,
                 "A message", BiometricSourceType.FACE);
 
-        verify(mStatusBarKeyguardViewManager).setKeyguardMessage(eq(message), any());
+        verify(mStatusBarKeyguardViewManager).setKeyguardMessage(eq(message), any(), any());
     }
 
     @Test
@@ -608,7 +623,8 @@
         mController.getKeyguardCallback().onBiometricError(FACE_ERROR_TIMEOUT,
                 "A message", BiometricSourceType.FACE);
 
-        verify(mStatusBarKeyguardViewManager, never()).setKeyguardMessage(eq(message), any());
+        verify(mStatusBarKeyguardViewManager, never()).setKeyguardMessage(
+                eq(message), any(), any());
     }
 
     @Test
@@ -1242,7 +1258,7 @@
     public void onBiometricFailed_resetFaceHelpMessageDeferral() {
         createController();
 
-        // WHEN face sends an onBiometricHelp BIOMETRIC_HELP_FACE_NOT_RECOGNIZED
+        // WHEN face sends an onBiometricAuthFailed
         mKeyguardUpdateMonitorCallback.onBiometricAuthFailed(BiometricSourceType.FACE);
 
         // THEN face help message deferral is reset
@@ -1331,7 +1347,9 @@
         verify(mStatusBarKeyguardViewManager)
                 .setKeyguardMessage(
                         eq(mContext.getString(R.string.keyguard_face_unlock_unavailable)),
-                        any());
+                        any(),
+                        any()
+                );
     }
 
     @Test
@@ -1471,6 +1489,71 @@
                 mContext.getString(R.string.keyguard_suggest_fingerprint));
     }
 
+    @Test
+    public void faceErrorMessageDroppedBecauseFingerprintMessageShowing() {
+        createController();
+        mController.setVisible(true);
+        mController.getKeyguardCallback().onBiometricHelp(BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED,
+                "fp not recognized", BiometricSourceType.FINGERPRINT);
+        clearInvocations(mRotateTextViewController);
+
+        onFaceLockoutError("lockout");
+        verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
+    }
+
+    @Test
+    public void faceUnlockedMessageShowsEvenWhenFingerprintMessageShowing() {
+        createController();
+        mController.setVisible(true);
+        mController.getKeyguardCallback().onBiometricHelp(BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED,
+                "fp not recognized", BiometricSourceType.FINGERPRINT);
+        clearInvocations(mRotateTextViewController);
+
+        when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(true);
+        when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(getCurrentUser()))
+                .thenReturn(true);
+        mController.getKeyguardCallback().onBiometricAuthenticated(0,
+                BiometricSourceType.FACE, false);
+        verifyIndicationMessage(
+                INDICATION_TYPE_BIOMETRIC_MESSAGE,
+                mContext.getString(R.string.keyguard_face_successful_unlock));
+    }
+
+    @Test
+    public void onTrustAgentErrorMessageDroppedBecauseFingerprintMessageShowing() {
+        createController();
+        mController.setVisible(true);
+        mController.getKeyguardCallback().onBiometricHelp(BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED,
+                "fp not recognized", BiometricSourceType.FINGERPRINT);
+        clearInvocations(mRotateTextViewController);
+
+        mKeyguardUpdateMonitorCallback.onTrustAgentErrorMessage("testMessage");
+        verifyNoMessage(INDICATION_TYPE_TRUST);
+        verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
+    }
+
+    @Test
+    public void trustGrantedMessageShowsEvenWhenFingerprintMessageShowing() {
+        createController();
+        mController.setVisible(true);
+        mController.getKeyguardCallback().onBiometricHelp(BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED,
+                "fp not recognized", BiometricSourceType.FINGERPRINT);
+        clearInvocations(mRotateTextViewController);
+
+        // GIVEN trust is granted
+        when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
+
+        // WHEN the showTrustGranted method is called
+        final String trustGrantedMsg = "testing trust granted message after fp message";
+        mController.getKeyguardCallback().onTrustGrantedForCurrentUser(
+                false, false, new TrustGrantFlags(0), trustGrantedMsg);
+
+        // THEN verify the trust granted message shows
+        verifyIndicationMessage(
+                INDICATION_TYPE_TRUST,
+                trustGrantedMsg);
+    }
+
     private void screenIsTurningOn() {
         when(mScreenLifecycle.getScreenState()).thenReturn(SCREEN_TURNING_ON);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index fe16347..dfbb6ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -54,7 +54,6 @@
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
-import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.shade.LargeScreenHeaderHelper
 import com.android.systemui.shade.data.repository.FakeShadeRepository
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -87,6 +86,7 @@
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
+import com.android.systemui.scene.shared.model.Scenes
 import org.mockito.MockitoAnnotations
 
 @SmallTest
@@ -313,48 +313,48 @@
             kosmos.fakeDeviceEntryRepository.setUnlocked(false)
             runCurrent()
             kosmos.sceneInteractor.changeScene(
-                toScene = SceneKey.Lockscreen,
+                toScene = Scenes.Lockscreen,
                 loggingReason = "reason"
             )
             runCurrent()
             assertThat(kosmos.deviceUnlockedInteractor.isDeviceUnlocked.value).isFalse()
-            assertThat(currentScene).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
 
             // Call start to begin hydrating based on the scene framework:
             underTest.start()
 
-            kosmos.sceneInteractor.changeScene(toScene = SceneKey.Bouncer, loggingReason = "reason")
+            kosmos.sceneInteractor.changeScene(toScene = Scenes.Bouncer, loggingReason = "reason")
             runCurrent()
-            assertThat(currentScene).isEqualTo(SceneKey.Bouncer)
+            assertThat(currentScene).isEqualTo(Scenes.Bouncer)
             assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD)
 
-            kosmos.sceneInteractor.changeScene(toScene = SceneKey.Shade, loggingReason = "reason")
+            kosmos.sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason")
             runCurrent()
-            assertThat(currentScene).isEqualTo(SceneKey.Shade)
+            assertThat(currentScene).isEqualTo(Scenes.Shade)
             assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED)
 
             kosmos.sceneInteractor.changeScene(
-                toScene = SceneKey.QuickSettings,
+                toScene = Scenes.QuickSettings,
                 loggingReason = "reason"
             )
             runCurrent()
-            assertThat(currentScene).isEqualTo(SceneKey.QuickSettings)
+            assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
             assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED)
 
             kosmos.sceneInteractor.changeScene(
-                toScene = SceneKey.Communal,
+                toScene = Scenes.Communal,
                 loggingReason = "reason"
             )
             runCurrent()
-            assertThat(currentScene).isEqualTo(SceneKey.Communal)
+            assertThat(currentScene).isEqualTo(Scenes.Communal)
             assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD)
 
             kosmos.sceneInteractor.changeScene(
-                toScene = SceneKey.Lockscreen,
+                toScene = Scenes.Lockscreen,
                 loggingReason = "reason"
             )
             runCurrent()
-            assertThat(currentScene).isEqualTo(SceneKey.Lockscreen)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
             assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD)
         }
 
@@ -377,25 +377,25 @@
             )
             kosmos.fakeDeviceEntryRepository.setUnlocked(true)
             runCurrent()
-            kosmos.sceneInteractor.changeScene(toScene = SceneKey.Gone, loggingReason = "reason")
+            kosmos.sceneInteractor.changeScene(toScene = Scenes.Gone, loggingReason = "reason")
             runCurrent()
             assertThat(kosmos.deviceUnlockedInteractor.isDeviceUnlocked.value).isTrue()
-            assertThat(currentScene).isEqualTo(SceneKey.Gone)
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
 
             // Call start to begin hydrating based on the scene framework:
             underTest.start()
 
-            kosmos.sceneInteractor.changeScene(toScene = SceneKey.Shade, loggingReason = "reason")
+            kosmos.sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason")
             runCurrent()
-            assertThat(currentScene).isEqualTo(SceneKey.Shade)
+            assertThat(currentScene).isEqualTo(Scenes.Shade)
             assertThat(statusBarState).isEqualTo(StatusBarState.SHADE)
 
             kosmos.sceneInteractor.changeScene(
-                toScene = SceneKey.QuickSettings,
+                toScene = Scenes.QuickSettings,
                 loggingReason = "reason"
             )
             runCurrent()
-            assertThat(currentScene).isEqualTo(SceneKey.QuickSettings)
+            assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
             assertThat(statusBarState).isEqualTo(StatusBarState.SHADE)
         }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
index 7d99d05..457d2f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
@@ -130,6 +131,7 @@
         onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
 
         verify(entry.representativeEntry!!).setSensitive(false, true)
+        verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true)
     }
 
     @Test
@@ -156,6 +158,7 @@
         onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
 
         verify(entry.representativeEntry!!).setSensitive(true, false)
+        verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false)
     }
 
     @Test
@@ -196,6 +199,7 @@
         onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
 
         verify(entry.representativeEntry!!).setSensitive(false, true)
+        verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true)
     }
 
     @Test
@@ -222,6 +226,7 @@
         onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
 
         verify(entry.representativeEntry!!).setSensitive(true, false)
+        verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false)
     }
 
     @Test
@@ -262,6 +267,7 @@
         onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
 
         verify(entry.representativeEntry!!).setSensitive(false, true)
+        verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true)
     }
 
     @Test
@@ -288,6 +294,7 @@
         onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
 
         verify(entry.representativeEntry!!).setSensitive(true, false)
+        verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false)
     }
 
     @Test
@@ -329,6 +336,7 @@
         onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
 
         verify(entry.representativeEntry!!).setSensitive(false, true)
+        verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true)
     }
 
     @Test
@@ -356,6 +364,7 @@
         onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
 
         verify(entry.representativeEntry!!).setSensitive(true, true)
+        verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false)
     }
 
     @Test
@@ -396,6 +405,7 @@
         onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
 
         verify(entry.representativeEntry!!).setSensitive(true, true)
+        verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true)
     }
 
     @Test
@@ -422,6 +432,7 @@
         onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
 
         verify(entry.representativeEntry!!).setSensitive(true, true)
+        verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false)
     }
 
     @Test
@@ -462,6 +473,7 @@
         onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
 
         verify(entry.representativeEntry!!).setSensitive(false, true)
+        verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true)
     }
 
     @Test
@@ -489,6 +501,7 @@
         onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
 
         verify(entry.representativeEntry!!).setSensitive(true, true)
+        verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false)
     }
 
     @Test
@@ -531,6 +544,7 @@
         onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
 
         verify(entry.representativeEntry!!).setSensitive(true, true)
+        verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true)
     }
 
     @Test
@@ -559,6 +573,7 @@
         onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
 
         verify(entry.representativeEntry!!).setSensitive(true, true)
+        verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false)
     }
 
     @Test
@@ -584,6 +599,7 @@
         onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
 
         verify(entry.representativeEntry!!, never()).setSensitive(any(), any())
+        verify(entry.representativeEntry!!.row!!, never()).setPublicExpanderVisible(any())
     }
 
     private fun fakeNotification(notifUserId: Int, needsRedaction: Boolean): ListEntry {
@@ -591,7 +607,11 @@
             mock<UserHandle>().apply { whenever(identifier).thenReturn(notifUserId) }
         val mockSbn: StatusBarNotification =
             mock<StatusBarNotification>().apply { whenever(user).thenReturn(mockUserHandle) }
-        val mockEntry = mock<NotificationEntry>().apply { whenever(sbn).thenReturn(mockSbn) }
+        val mockRow: ExpandableNotificationRow = mock<ExpandableNotificationRow>()
+        val mockEntry = mock<NotificationEntry>().apply {
+            whenever(sbn).thenReturn(mockSbn)
+            whenever(row).thenReturn(mockRow)
+        }
         whenever(lockscreenUserManager.needsRedaction(mockEntry)).thenReturn(needsRedaction)
         whenever(mockEntry.rowExists()).thenReturn(true)
         return object : ListEntry("key", 0) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
index 73c49c0..115a0d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
 import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
+import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation
 import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.eq
@@ -46,6 +47,7 @@
 import org.junit.runner.RunWith
 import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.inOrder
+import org.mockito.Mockito.spy
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
 import org.mockito.Mockito.`when` as whenever
@@ -141,12 +143,14 @@
     fun changeIsChildInGroup_asyncHybirdFlagEnabled_needReInflation() {
         // Given: an Entry that is not child in group
         // AsyncHybridViewInflation flag is enabled
-        whenever(groupMembershipManager.isChildInGroup(entry)).thenReturn(false)
+        val spySbn = spy(entry.sbn)
+        entry.sbn = spySbn
+        whenever(spySbn.isAppOrSystemGroupChild).thenReturn(false)
         val oldAdjustment = adjustmentProvider.calculateAdjustment(entry)
         assertThat(oldAdjustment.isChildInGroup).isFalse()
 
         // When: the Entry becomes a group child
-        whenever(groupMembershipManager.isChildInGroup(entry)).thenReturn(true)
+        whenever(spySbn.isAppOrSystemGroupChild).thenReturn(true)
         val newAdjustment = adjustmentProvider.calculateAdjustment(entry)
         assertThat(newAdjustment.isChildInGroup).isTrue()
         assertThat(newAdjustment).isNotEqualTo(oldAdjustment)
@@ -160,12 +164,14 @@
     fun changeIsChildInGroup_asyncHybirdFlagDisabled_noNeedForReInflation() {
         // Given: an Entry that is not child in group
         // AsyncHybridViewInflation flag is disabled
-        whenever(groupMembershipManager.isChildInGroup(entry)).thenReturn(false)
+        val spySbn = spy(entry.sbn)
+        entry.sbn = spySbn
+        whenever(spySbn.isAppOrSystemGroupChild).thenReturn(false)
         val oldAdjustment = adjustmentProvider.calculateAdjustment(entry)
         assertThat(oldAdjustment.isChildInGroup).isFalse()
 
         // When: the Entry becomes a group child
-        whenever(groupMembershipManager.isChildInGroup(entry)).thenReturn(true)
+        whenever(spySbn.isAppOrSystemGroupChild).thenReturn(true)
         val newAdjustment = adjustmentProvider.calculateAdjustment(entry)
         assertThat(newAdjustment.isChildInGroup).isTrue()
         assertThat(newAdjustment).isNotEqualTo(oldAdjustment)
@@ -173,4 +179,24 @@
         // Then: need no re-inflation
         assertFalse(NotifUiAdjustment.needReinflate(oldAdjustment, newAdjustment))
     }
+
+    @Test
+    @EnableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
+    fun changeIsGroupSummary_needReInflation() {
+        // Given: an Entry that is not a group summary
+        val spySbn = spy(entry.sbn)
+        entry.sbn = spySbn
+        whenever(spySbn.isAppOrSystemGroupSummary).thenReturn(false)
+        val oldAdjustment = adjustmentProvider.calculateAdjustment(entry)
+        assertThat(oldAdjustment.isGroupSummary).isFalse()
+
+        // When: the Entry becomes a group summary
+        whenever(spySbn.isAppOrSystemGroupSummary).thenReturn(true)
+        val newAdjustment = adjustmentProvider.calculateAdjustment(entry)
+        assertThat(newAdjustment.isGroupSummary).isTrue()
+        assertThat(newAdjustment).isNotEqualTo(oldAdjustment)
+
+        // Then: Need re-inflation
+        assertTrue(NotifUiAdjustment.needReinflate(oldAdjustment, newAdjustment))
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 49ba915..42a6924 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -69,6 +69,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
+import com.android.systemui.statusbar.notification.shared.NotificationContentAlphaOptimization;
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 
@@ -330,6 +331,61 @@
     }
 
     @Test
+    @EnableFlags(NotificationContentAlphaOptimization.FLAG_NAME)
+    public void setHideSensitive_shouldNotDisturbAnimation() throws Exception {
+        //Given: A row that is during alpha animation
+        ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+
+        assertEquals(row.getPrivateLayout(), row.getContentView());
+        row.setContentAlpha(0.5f);
+
+        //When: Set its hideSensitive without changing the content view to show
+        row.setHideSensitive(
+                /* hideSensitive= */ false,
+                /* animated= */ false,
+                /* delay=  */ 0L,
+                /* duration=  */ 0L
+        );
+        assertEquals(row.getPrivateLayout(), row.getContentView());
+
+        //Then: The alpha value should not be reset
+        assertEquals(0.5f, row.getPrivateLayout().getAlpha(), 0);
+    }
+
+    @Test
+    @EnableFlags(NotificationContentAlphaOptimization.FLAG_NAME)
+    public void setHideSensitive_changeContent_shouldNotDisturbAnimation() throws Exception {
+
+        // Given: A sensitive row that has public version but is not hiding sensitive,
+        // and is during an animation that sets its alpha value to be 0.5f
+        Notification publicNotif = mNotificationTestHelper.createNotification();
+        publicNotif.publicVersion = mNotificationTestHelper.createNotification();
+        ExpandableNotificationRow row = mNotificationTestHelper.createRow(publicNotif);
+        row.setSensitive(true, false);
+        row.setContentAlpha(0.5f);
+
+        assertEquals(0.5f, row.getPrivateLayout().getAlpha(), 0);
+        assertEquals(View.VISIBLE, row.getPrivateLayout().getVisibility());
+
+        // When: Change its hideSensitive and changes the content view to show the public version
+        row.setHideSensitive(
+                /* hideSensitive= */ true,
+                /* animated= */ false,
+                /* delay=  */ 0L,
+                /* duration=  */ 0L
+        );
+
+        // Then: The alpha value of private layout should be reset to 1, private layout be
+        // INVISIBLE;
+        // The alpha value of public layout should be 0.5 to preserve the animation state, public
+        // layout should be VISIBLE
+        assertEquals(View.INVISIBLE, row.getPrivateLayout().getVisibility());
+        assertEquals(1f, row.getPrivateLayout().getAlpha(), 0);
+        assertEquals(View.VISIBLE, row.getPublicLayout().getVisibility());
+        assertEquals(0.5f, row.getPublicLayout().getAlpha(), 0);
+    }
+
+    @Test
     public void testReinflatedOnDensityChange() throws Exception {
         ExpandableNotificationRow row = mNotificationTestHelper.createRow();
         NotificationChildrenContainer mockContainer = mock(NotificationChildrenContainer.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
index dbf7b6c..012ff2e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
@@ -38,6 +38,7 @@
 import android.view.View
 import android.view.accessibility.accessibilityManager
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.internal.logging.MetricsLogger
 import com.android.internal.logging.UiEventLogger
 import com.android.internal.logging.metricsLogger
@@ -55,8 +56,7 @@
 import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.settings.UserContextProvider
 import com.android.systemui.shade.shadeControllerSceneImpl
 import com.android.systemui.statusbar.NotificationEntryHelper
@@ -602,9 +602,9 @@
     private fun setIsLockscreenOrShadeVisible(isVisible: Boolean) {
         val key =
             if (isVisible) {
-                SceneKey.Lockscreen
+                Scenes.Lockscreen
             } else {
-                SceneKey.Bouncer
+                Scenes.Bouncer
             }
         sceneInteractor.changeScene(key, "test")
         sceneInteractor.setTransitionState(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
index be976a1c..1f38a73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
@@ -16,11 +16,17 @@
 
 package com.android.systemui.statusbar.notification.stack;
 
+import static org.junit.Assert.assertNull;
+
+import android.app.Notification;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.NotificationHeaderView;
 import android.view.View;
+import android.widget.RemoteViews;
 
 import androidx.test.filters.SmallTest;
 
@@ -28,6 +34,7 @@
 import com.android.systemui.statusbar.notification.SourceType;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper;
 
 import org.junit.Assert;
@@ -40,6 +47,7 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
+//@DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
 public class NotificationChildrenContainerTest extends SysuiTestCase {
 
     private ExpandableNotificationRow mGroup;
@@ -138,6 +146,7 @@
     }
 
     @Test
+    @DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
     public void testLowPriorityHeaderCleared() {
         mGroup.setIsLowPriority(true);
         NotificationHeaderView lowPriorityHeaderView =
@@ -145,11 +154,12 @@
         Assert.assertEquals(View.VISIBLE, lowPriorityHeaderView.getVisibility());
         Assert.assertSame(mChildrenContainer, lowPriorityHeaderView.getParent());
         mGroup.setIsLowPriority(false);
-        Assert.assertNull(lowPriorityHeaderView.getParent());
-        Assert.assertNull(mChildrenContainer.getLowPriorityViewWrapper());
+        assertNull(lowPriorityHeaderView.getParent());
+        assertNull(mChildrenContainer.getLowPriorityViewWrapper());
     }
 
     @Test
+    @DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
     public void testRecreateNotificationHeader_hasHeader() {
         mChildrenContainer.recreateNotificationHeader(null, false);
         Assert.assertNotNull("Children container must have a header after recreation",
@@ -157,6 +167,76 @@
     }
 
     @Test
+    @EnableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
+    public void testSetLowPriorityWithAsyncInflation_noHeaderReInflation() {
+        mChildrenContainer.setIsLowPriority(true);
+        assertNull("We don't inflate header from the main thread with Async "
+                + "Inflation enabled", mChildrenContainer.getCurrentHeaderView());
+    }
+
+    @Test
+    @EnableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
+    public void setLowPriorityBeforeLowPriorityHeaderSet() {
+
+        //Given: the children container does not have a low-priority header, and is not low-priority
+        assertNull(mChildrenContainer.getLowPriorityViewWrapper());
+        mGroup.setIsLowPriority(false);
+
+        //When: set the children container to be low-priority and set the low-priority header
+        mGroup.setIsLowPriority(true);
+        mGroup.setLowPriorityGroupHeader(createHeaderView(/* lowPriorityHeader= */ true));
+
+        //Then: the low-priority group header should be visible
+        NotificationHeaderView lowPriorityHeaderView =
+                mChildrenContainer.getLowPriorityViewWrapper().getNotificationHeader();
+        Assert.assertEquals(View.VISIBLE, lowPriorityHeaderView.getVisibility());
+        Assert.assertSame(mChildrenContainer, lowPriorityHeaderView.getParent());
+
+        //When: set the children container to be not low-priority and set the normal header
+        mGroup.setIsLowPriority(false);
+        mGroup.setGroupHeader(createHeaderView(/* lowPriorityHeader= */ false));
+
+        //Then: the low-priority group header should not be visible , normal header should be
+        // visible
+        Assert.assertEquals(View.INVISIBLE, lowPriorityHeaderView.getVisibility());
+        Assert.assertEquals(
+                View.VISIBLE,
+                mChildrenContainer.getNotificationHeaderWrapper().getNotificationHeader()
+                        .getVisibility()
+        );
+    }
+
+    @Test
+    @EnableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
+    public void changeLowPriorityAfterHeaderSet() {
+
+        //Given: the children container does not have headers, and is not low-priority
+        assertNull(mChildrenContainer.getLowPriorityViewWrapper());
+        assertNull(mChildrenContainer.getNotificationHeaderWrapper());
+        mGroup.setIsLowPriority(false);
+
+        //When: set the set the normal header
+        mGroup.setGroupHeader(createHeaderView(/* lowPriorityHeader= */ false));
+
+        //Then: the group header should be visible
+        NotificationHeaderView headerView =
+                mChildrenContainer.getNotificationHeaderWrapper().getNotificationHeader();
+        Assert.assertEquals(View.VISIBLE, headerView.getVisibility());
+        Assert.assertSame(mChildrenContainer, headerView.getParent());
+
+        //When: set the set the row to be low priority, and set the low-priority header
+        mGroup.setIsLowPriority(true);
+        mGroup.setLowPriorityGroupHeader(createHeaderView(/* lowPriorityHeader= */ true));
+
+        //Then: the header view should not be visible, the low-priority group header should be
+        // visible
+        Assert.assertEquals(View.INVISIBLE, headerView.getVisibility());
+        NotificationHeaderView lowPriorityHeaderView =
+                mChildrenContainer.getLowPriorityViewWrapper().getNotificationHeader();
+        Assert.assertEquals(View.VISIBLE, lowPriorityHeaderView.getVisibility());
+    }
+
+    @Test
     public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_last_child() {
         List<ExpandableNotificationRow> children = mChildrenContainer.getAttachedChildren();
         ExpandableNotificationRow notificationRow = children.get(children.size() - 1);
@@ -170,6 +250,7 @@
     }
 
     @Test
+    @DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
     public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_header() {
         NotificationHeaderViewWrapper header = mChildrenContainer.getNotificationHeaderWrapper();
         Assert.assertEquals(0f, header.getTopRoundness(), 0.001f);
@@ -180,6 +261,7 @@
     }
 
     @Test
+    @DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
     public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_headerLowPriority() {
         mChildrenContainer.setIsLowPriority(true);
 
@@ -190,4 +272,17 @@
 
         Assert.assertEquals(1f, header.getTopRoundness(), 0.001f);
     }
+
+    private NotificationHeaderView createHeaderView(boolean lowPriority) {
+        Notification notification = mNotificationTestHelper.createNotification();
+        final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
+                notification);
+        RemoteViews headerRemoteViews;
+        if (lowPriority) {
+            headerRemoteViews = builder.makeLowPriorityContentView(true);
+        } else {
+            headerRemoteViews = builder.makeNotificationGroupHeader();
+        }
+        return (NotificationHeaderView) headerRemoteViews.apply(getContext(), mChildrenContainer);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorTest.kt
new file mode 100644
index 0000000..1c6bda9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorTest.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.notification.stack.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.power.data.repository.fakePowerRepository
+import com.android.systemui.power.shared.model.WakefulnessState
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class NotificationStackInteractorTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    val underTest
+        get() = kosmos.notificationStackInteractor
+
+    @Test
+    fun testIsShowingOnLockscreen_falseWhenViewingShade() =
+        kosmos.testScope.runTest {
+            val onLockscreen by collectLastValue(underTest.isShowingOnLockscreen)
+
+            // WHEN shade is open
+            kosmos.fakeKeyguardRepository.setStatusBarState(StatusBarState.SHADE)
+            runCurrent()
+
+            // THEN notifications are not showing on lockscreen
+            assertThat(onLockscreen).isFalse()
+        }
+
+    @Test
+    fun testIsShowingOnLockscreen_trueWhenViewingKeyguard() =
+        kosmos.testScope.runTest {
+            val onLockscreen by collectLastValue(underTest.isShowingOnLockscreen)
+
+            // WHEN on keyguard
+            kosmos.fakeKeyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
+            runCurrent()
+
+            // THEN notifications are showing on lockscreen
+            assertThat(onLockscreen).isTrue()
+        }
+
+    @Test
+    fun testIsShowingOnLockscreen_trueWhenStartingToSleep() =
+        kosmos.testScope.runTest {
+            val onLockscreen by collectLastValue(underTest.isShowingOnLockscreen)
+
+            // WHEN shade is open
+            kosmos.fakeKeyguardRepository.setStatusBarState(StatusBarState.SHADE)
+            // AND device is starting to go to sleep
+            kosmos.fakePowerRepository.updateWakefulness(WakefulnessState.STARTING_TO_SLEEP)
+            runCurrent()
+
+            // THEN notifications are showing on lockscreen
+            assertThat(onLockscreen).isTrue()
+        }
+}
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 3a94295d..84156ee1 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
@@ -73,6 +73,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.compose.animation.scene.ObservableTransitionState;
 import com.android.internal.colorextraction.ColorExtractor;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -95,8 +96,7 @@
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.communal.data.repository.CommunalRepository;
 import com.android.systemui.communal.domain.interactor.CommunalInteractor;
-import com.android.systemui.communal.shared.model.CommunalSceneKey;
-import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState;
+import com.android.systemui.communal.shared.model.CommunalScenes;
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FakeFeatureFlags;
@@ -842,16 +842,16 @@
     @Test
     public void testEnteringGlanceableHub_updatesScrim() {
         // Transition to the glanceable hub.
-        mCommunalRepository.setTransitionState(flowOf(new ObservableCommunalTransitionState.Idle(
-                CommunalSceneKey.Communal.INSTANCE)));
+        mCommunalRepository.setTransitionState(flowOf(new ObservableTransitionState.Idle(
+                CommunalScenes.Communal)));
         mTestScope.getTestScheduler().runCurrent();
 
         // ScrimState also transitions.
         verify(mScrimController).transitionTo(ScrimState.GLANCEABLE_HUB);
 
         // Transition away from the glanceable hub.
-        mCommunalRepository.setTransitionState(flowOf(new ObservableCommunalTransitionState.Idle(
-                CommunalSceneKey.Blank.INSTANCE)));
+        mCommunalRepository.setTransitionState(flowOf(new ObservableTransitionState.Idle(
+                CommunalScenes.Blank)));
         mTestScope.getTestScheduler().runCurrent();
 
         // ScrimState goes back to UNLOCKED.
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 1687ccb..443dd6a 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
@@ -20,6 +20,7 @@
 import android.app.StatusBarManager.WINDOW_STATE_HIDING
 import android.app.StatusBarManager.WINDOW_STATE_SHOWING
 import android.app.StatusBarManager.WINDOW_STATUS_BAR
+import android.view.InputDevice
 import android.view.LayoutInflater
 import android.view.MotionEvent
 import android.view.View
@@ -233,14 +234,35 @@
     }
 
     @Test
-    fun shadeIsExpandedOnStatusIconClick() {
+    fun shadeIsExpandedOnStatusIconMouseClick() {
         val view = createViewMock()
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             controller = createAndInitController(view)
         }
         val statusContainer = view.requireViewById<View>(R.id.system_icons)
-        statusContainer.performClick()
-        verify(shadeViewController).expand(any())
+        statusContainer.dispatchTouchEvent(
+            getActionUpEventFromSource(InputDevice.SOURCE_MOUSE)
+        )
+        verify(shadeControllerImpl).animateExpandShade()
+    }
+
+    @Test
+    fun statusIconContainerIsNotHandlingTouchScreenTouches() {
+        val view = createViewMock()
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            controller = createAndInitController(view)
+        }
+        val statusContainer = view.requireViewById<View>(R.id.system_icons)
+        val handled = statusContainer.dispatchTouchEvent(
+            getActionUpEventFromSource(InputDevice.SOURCE_TOUCHSCREEN)
+        )
+        assertThat(handled).isFalse()
+    }
+
+    private fun getActionUpEventFromSource(source: Int): MotionEvent {
+        val ev = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0f, 0f, 0)
+        ev.source = source
+        return ev
     }
 
     @Test
@@ -250,7 +272,7 @@
             controller = createAndInitController(view)
         }
         view.performClick()
-        verify(shadeViewController, never()).expand(any())
+        verify(shadeControllerImpl, never()).animateExpandShade()
     }
 
     private fun getCommandQueueCallback(): CommandQueue.Callbacks {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
index 5e8b62e..fd2dead 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
@@ -26,6 +26,7 @@
 import android.view.MotionEvent
 import android.view.PrivacyIndicatorBounds
 import android.view.RoundedCorners
+import android.view.View
 import android.view.WindowInsets
 import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
@@ -50,6 +51,8 @@
 class PhoneStatusBarViewTest : SysuiTestCase() {
 
     private lateinit var view: PhoneStatusBarView
+    private val systemIconsContainer: View
+        get() = view.requireViewById(R.id.system_icons)
 
     private val contentInsetsProvider = mock<StatusBarContentInsetsProvider>()
     private val windowController = mock<StatusBarWindowController>()
@@ -62,6 +65,7 @@
         )
         mDependency.injectTestDependency(DarkIconDispatcher::class.java, mock<DarkIconDispatcher>())
         mDependency.injectTestDependency(StatusBarWindowController::class.java, windowController)
+        context.ensureTestableResources()
         view = spy(createStatusBarView())
         whenever(view.rootWindowInsets).thenReturn(emptyWindowInsets())
         whenever(contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation())
@@ -217,7 +221,7 @@
 
         val newInsets = Insets.NONE
         whenever(contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation())
-                .thenReturn(newInsets)
+            .thenReturn(newInsets)
         view.onConfigurationChanged(Configuration())
 
         assertThat(view.paddingLeft).isEqualTo(previousInsets.left)
@@ -239,7 +243,7 @@
 
         val newInsets = Insets.NONE
         whenever(contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation())
-                .thenReturn(newInsets)
+            .thenReturn(newInsets)
         configuration.densityDpi = 456
         view.onConfigurationChanged(configuration)
 
@@ -262,7 +266,7 @@
 
         val newInsets = Insets.NONE
         whenever(contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation())
-                .thenReturn(newInsets)
+            .thenReturn(newInsets)
         configuration.fontScale = 2f
         view.onConfigurationChanged(configuration)
 
@@ -273,6 +277,19 @@
     }
 
     @Test
+    fun onConfigurationChanged_systemIconsHeightChanged_containerHeightIsUpdated() {
+        val newHeight = 123456
+        context.orCreateTestableResources.addOverride(
+            R.dimen.status_bar_system_icons_height,
+            newHeight
+        )
+
+        view.onConfigurationChanged(Configuration())
+
+        assertThat(systemIconsContainer.layoutParams.height).isEqualTo(newHeight)
+    }
+
+    @Test
     fun onApplyWindowInsets_updatesLeftTopRightPaddingsBasedOnInsets() {
         val insets = Insets.of(/* left = */ 90, /* top = */ 10, /* right = */ 45, /* bottom = */ 50)
         whenever(contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index bd7406a..f050857 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -86,6 +86,7 @@
 import com.android.systemui.navigationbar.TaskbarDelegate;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
+import com.android.systemui.scene.domain.interactor.SceneInteractor;
 import com.android.systemui.shade.NotificationShadeWindowView;
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.shade.ShadeExpansionChangeEvent;
@@ -97,6 +98,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.unfold.SysUIUnfoldComponent;
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
+import com.android.systemui.util.kotlin.JavaAdapter;
 
 import com.google.common.truth.Truth;
 
@@ -222,7 +224,9 @@
                         () -> mock(WindowManagerLockscreenVisibilityInteractor.class),
                         () -> mock(KeyguardDismissActionInteractor.class),
                         mSelectedUserInteractor,
-                        () -> mock(KeyguardSurfaceBehindInteractor.class)) {
+                        () -> mock(KeyguardSurfaceBehindInteractor.class),
+                        mock(JavaAdapter.class),
+                        () -> mock(SceneInteractor.class)) {
                     @Override
                     public ViewRootImpl getViewRootImpl() {
                         return mViewRootImpl;
@@ -730,7 +734,9 @@
                         () -> mock(WindowManagerLockscreenVisibilityInteractor.class),
                         () -> mock(KeyguardDismissActionInteractor.class),
                         mSelectedUserInteractor,
-                        () -> mock(KeyguardSurfaceBehindInteractor.class)) {
+                        () -> mock(KeyguardSurfaceBehindInteractor.class),
+                        mock(JavaAdapter.class),
+                        () -> mock(SceneInteractor.class)) {
                     @Override
                     public ViewRootImpl getViewRootImpl() {
                         return mViewRootImpl;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 41514ce..938b2f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -79,6 +79,7 @@
 import com.android.systemui.shade.data.repository.FakeShadeRepository;
 import com.android.systemui.shade.data.repository.ShadeAnimationRepository;
 import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorLegacyImpl;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationClickNotifier;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationPresenter;
@@ -130,6 +131,8 @@
     @Mock
     private ActivityStarter mActivityStarter;
     @Mock
+    private CommandQueue mCommandQueue;
+    @Mock
     private NotificationClickNotifier mClickNotifier;
     @Mock
     private StatusBarStateController mStatusBarStateController;
@@ -236,6 +239,7 @@
                         mVisibilityProvider,
                         headsUpManager,
                         mActivityStarter,
+                        mCommandQueue,
                         mClickNotifier,
                         mStatusBarKeyguardViewManager,
                         mock(KeyguardManager.class),
@@ -257,7 +261,9 @@
                         mock(NotificationShadeWindowController.class),
                         mActivityTransitionAnimator,
                         new ShadeAnimationInteractorLegacyImpl(
-                                new ShadeAnimationRepository(), new FakeShadeRepository()),
+                                new ShadeAnimationRepository(),
+                                new FakeShadeRepository()
+                        ),
                         notificationAnimationProvider,
                         mock(LaunchFullScreenIntentProvider.class),
                         mPowerInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
index b958f35..a41bc0d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
@@ -616,7 +616,7 @@
     dataType: SignalIcon.MobileIconGroup? = THREE_G,
     subId: Int? = 1,
     carrierId: Int? = UNKNOWN_CARRIER_ID,
-    inflateStrength: Boolean? = false,
+    inflateStrength: Boolean = false,
     activity: Int? = null,
     carrierNetworkChange: Boolean = false,
     roaming: Boolean = 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 1f27a28..47899a6 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
@@ -38,9 +38,12 @@
 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 junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.isActive
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
@@ -156,14 +159,35 @@
             val model2 = underTest.viewModelForSub(2, StatusBarLocation.QS)
 
             // Both impls are cached
-            assertThat(underTest.mobileIconSubIdCache)
-                .containsExactly(1, model1.commonImpl, 2, model2.commonImpl)
+            assertThat(underTest.reuseCache.keys).containsExactly(1, 2)
 
             // SUB_1 is removed from the list...
             interactor.filteredSubscriptions.value = listOf(SUB_2)
 
             // ... and dropped from the cache
-            assertThat(underTest.mobileIconSubIdCache).containsExactly(2, model2.commonImpl)
+            assertThat(underTest.reuseCache.keys).containsExactly(2)
+        }
+
+    @Test
+    fun caching_invalidatedViewModelsAreCanceled() =
+        testScope.runTest {
+            // Retrieve models to trigger caching
+            val model1 = underTest.viewModelForSub(1, StatusBarLocation.HOME)
+            val model2 = underTest.viewModelForSub(2, StatusBarLocation.QS)
+
+            var scope1 = underTest.reuseCache[1]?.second
+            var scope2 = underTest.reuseCache[2]?.second
+
+            // Scopes are not canceled
+            assertTrue(scope1!!.isActive)
+            assertTrue(scope2!!.isActive)
+
+            // SUB_1 is removed from the list...
+            interactor.filteredSubscriptions.value = listOf(SUB_2)
+
+            // scope1 is canceled
+            assertFalse(scope1!!.isActive)
+            assertTrue(scope2!!.isActive)
         }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
index d465b47..c07f289 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
@@ -239,7 +239,9 @@
 
             // WHEN all of the connections are OOS
             i1.isInService.value = false
+            i1.isEmergencyOnly.value = false
             i2.isInService.value = false
+            i2.isEmergencyOnly.value = false
 
             // THEN the value is propagated to this interactor
             assertThat(latest).isTrue()
@@ -256,6 +258,7 @@
 
             // WHEN all of the connections are OOS
             i1.isInService.value = false
+            i1.isEmergencyOnly.value = false
 
             // THEN the value is propagated to this interactor
             assertThat(latest).isTrue()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
index cd0652e..ec6642d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
@@ -80,6 +80,7 @@
             // GIVEN all icons are OOS
             val i1 = mobileIconsInteractor.getMobileConnectionInteractorForSubId(1)
             i1.isInService.value = false
+            i1.isEmergencyOnly.value = false
 
             // GIVEN apm is disabled
             airplaneModeRepository.setIsAirplaneMode(false)
@@ -99,6 +100,7 @@
             // GIVEN all icons are not OOS
             val i1 = mobileIconsInteractor.getMobileConnectionInteractorForSubId(1)
             i1.isInService.value = true
+            i1.isEmergencyOnly.value = false
 
             // GIVEN apm is disabled
             airplaneModeRepository.setIsAirplaneMode(false)
@@ -108,6 +110,35 @@
         }
 
     @Test
+    fun icon_nullWhenShouldNotShow_isEmergencyOnly() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.icon)
+
+            // GIVEN satellite is allowed
+            repo.isSatelliteAllowedForCurrentLocation.value = true
+
+            // GIVEN all icons are OOS
+            val i1 = mobileIconsInteractor.getMobileConnectionInteractorForSubId(1)
+            i1.isInService.value = false
+            i1.isEmergencyOnly.value = false
+
+            // GIVEN apm is disabled
+            airplaneModeRepository.setIsAirplaneMode(false)
+
+            // Wait for delay to be completed
+            advanceTimeBy(10.seconds)
+
+            // THEN icon is set because we don't have service
+            assertThat(latest).isInstanceOf(Icon::class.java)
+
+            // GIVEN the connection is emergency only
+            i1.isEmergencyOnly.value = true
+
+            // THEN icon is null because we have emergency connection
+            assertThat(latest).isNull()
+        }
+
+    @Test
     fun icon_nullWhenShouldNotShow_apmIsEnabled() =
         testScope.runTest {
             val latest by collectLastValue(underTest.icon)
@@ -118,6 +149,7 @@
             // GIVEN all icons are OOS
             val i1 = mobileIconsInteractor.getMobileConnectionInteractorForSubId(1)
             i1.isInService.value = false
+            i1.isEmergencyOnly.value = false
 
             // GIVEN apm is enabled
             airplaneModeRepository.setIsAirplaneMode(true)
@@ -138,6 +170,7 @@
             // GIVEN all icons are OOS
             val i1 = mobileIconsInteractor.getMobileConnectionInteractorForSubId(1)
             i1.isInService.value = false
+            i1.isEmergencyOnly.value = false
 
             // GIVEN apm is disabled
             airplaneModeRepository.setIsAirplaneMode(false)
@@ -161,6 +194,7 @@
             // GIVEN all icons are OOS
             val i1 = mobileIconsInteractor.getMobileConnectionInteractorForSubId(1)
             i1.isInService.value = false
+            i1.isEmergencyOnly.value = false
 
             // GIVEN apm is disabled
             airplaneModeRepository.setIsAirplaneMode(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
index 766a5ce..5d34120 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
@@ -200,4 +200,25 @@
         assertThat(connection.bind()).isFalse();
         verify(mContext).unbindService(connection);
     }
+
+    @Test
+    public void testUnbindDoesNotCallUnbindServiceWhenBindThrowsError() {
+        ObservableServiceConnection<Foo> connection = new ObservableServiceConnection<>(mContext,
+                mIntent, mUserTracker, mExecutor, mTransformer);
+        connection.addCallback(mCallback);
+
+        when(mContext.bindServiceAsUser(eq(mIntent), eq(connection), anyInt(),
+                eq(UserHandle.of(MAIN_USER_ID))))
+                .thenThrow(new SecurityException());
+
+        // Verify that bind returns false and we properly unbind.
+        assertThat(connection.bind()).isFalse();
+        verify(mContext).unbindService(connection);
+
+        clearInvocations(mContext);
+
+        // Ensure unbind after the failed bind has no effect.
+        connection.unbind();
+        verify(mContext, never()).unbindService(eq(connection));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
index 23a9207..ed07ad2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
@@ -21,21 +21,40 @@
 
 import android.os.Build;
 import android.os.PowerManager;
+import android.platform.test.flag.junit.FlagsParameterization;
+import android.platform.test.flag.junit.SetFlagsRule;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
+import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.After;
+import org.junit.Assume;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.List;
 
 @SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
 public class WakeLockTest extends SysuiTestCase {
 
+    @Parameterized.Parameters(name = "{0}")
+    public static List<FlagsParameterization> getFlags() {
+        return FlagsParameterization.allCombinationsOf(
+                Flags.FLAG_DELAYED_WAKELOCK_RELEASE_ON_BACKGROUND_THREAD);
+    }
+
+    @Rule public final SetFlagsRule mSetFlagsRule;
+
+    public WakeLockTest(FlagsParameterization flags) {
+        mSetFlagsRule = new SetFlagsRule(SetFlagsRule.DefaultInitValueType.NULL_DEFAULT, flags);
+    }
+
     private static final String WHY = "test";
     WakeLock mWakeLock;
     PowerManager.WakeLock mInner;
@@ -91,10 +110,7 @@
 
     @Test
     public void prodBuild_wakeLock_releaseWithoutAcquire_noThrow() {
-        if (Build.IS_ENG) {
-            return;
-        }
-
+        Assume.assumeFalse(Build.IS_ENG);
         // shouldn't throw an exception on production builds
         mWakeLock.release(WHY);
     }
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 d2e0386..3a6324d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -61,7 +61,6 @@
 import android.widget.SeekBar;
 
 import androidx.test.core.view.MotionEventBuilder;
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.jank.InteractionJankMonitor;
@@ -502,7 +501,6 @@
     }
 
     @Test
-    @FlakyTest(bugId = 326204750)
     public void dialogDestroy_removesPostureControllerCallback() {
         verify(mPostureController, never()).removeCallback(any());
         mDialog.destroy();
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 a930860..fbefb0e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -609,6 +609,7 @@
                 mSysUiState,
                 mFeatureFlags,
                 mNotifPipelineFlags,
+                syncExecutor,
                 syncExecutor);
         mBubblesManager.addNotifCallback(mNotifCallback);
 
@@ -651,7 +652,7 @@
     }
 
     @Test
-    public void dreamingHidesBubbles() throws RemoteException {
+    public void bubblesHiddenWhileDreaming() throws RemoteException {
         mBubbleController.updateBubble(mBubbleEntry);
         assertTrue(mBubbleController.hasBubbles());
         assertThat(mBubbleController.getStackView().getVisibility()).isEqualTo(View.VISIBLE);
@@ -662,7 +663,17 @@
                 mKeyguardStateControllerCallbackCaptor.getValue();
         callback.onKeyguardShowingChanged();
 
+        // Dreaming should hide bubbles
         assertThat(mBubbleController.getStackView().getVisibility()).isEqualTo(View.INVISIBLE);
+
+        // Finish dreaming should show bubbles
+        mNotificationShadeWindowController.setDreaming(false);
+        when(mIDreamManager.isDreamingOrInPreview()).thenReturn(false); // dreaming finished
+
+        // Dreaming updates come through mNotificationShadeWindowController
+        mNotificationShadeWindowController.notifyStateChangedCallbacks();
+
+        assertThat(mBubbleController.getStackView().getVisibility()).isEqualTo(View.VISIBLE);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/utils/src/android/content/ContextKosmos.kt b/packages/SystemUI/tests/utils/src/android/content/ContextKosmos.kt
index f6ddfcc..185deea 100644
--- a/packages/SystemUI/tests/utils/src/android/content/ContextKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/android/content/ContextKosmos.kt
@@ -20,5 +20,6 @@
 import com.android.systemui.kosmos.testCase
 import com.android.systemui.util.mockito.mock
 
-var Kosmos.applicationContext: Context by Kosmos.Fixture { testCase.context }
+var Kosmos.applicationContext: Context by
+    Kosmos.Fixture { testCase.context.apply { ensureTestableResources() } }
 val Kosmos.mockedContext: Context by Kosmos.Fixture { mock<Context>() }
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/assist/data/repository/AssistRepositoryKosmos.kt
similarity index 78%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/assist/data/repository/AssistRepositoryKosmos.kt
index 8ad0a08..96155ed 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/assist/data/repository/AssistRepositoryKosmos.kt
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.systemui.volume.panel.component.mediaoutput
+package com.android.systemui.assist.data.repository
 
-import dagger.Module
+import com.android.systemui.kosmos.Kosmos
 
-@Module interface MediaOutputModule
+val Kosmos.assistRepository by Kosmos.Fixture { AssistRepository() }
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/assist/domain/interactor/AssistInteractorKosmos.kt
similarity index 70%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/assist/domain/interactor/AssistInteractorKosmos.kt
index 8ad0a08..c3c1131 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/assist/domain/interactor/AssistInteractorKosmos.kt
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.volume.panel.component.mediaoutput
+package com.android.systemui.assist.domain.interactor
 
-import dagger.Module
+import com.android.systemui.assist.data.repository.assistRepository
+import com.android.systemui.kosmos.Kosmos
 
-@Module interface MediaOutputModule
+val Kosmos.assistInteractor by Kosmos.Fixture { AssistInteractor(assistRepository) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt
index 3b5ff38..1b951d9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt
@@ -19,6 +19,7 @@
 
 import android.util.Size
 import com.android.systemui.biometrics.shared.model.DisplayRotation
+import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
@@ -33,6 +34,9 @@
     private val _currentDisplaySize = MutableStateFlow<Size>(Size(0, 0))
     override val currentDisplaySize: StateFlow<Size> = _currentDisplaySize.asStateFlow()
 
+    private val _isLargeScreen = MutableStateFlow<Boolean>(false)
+    override val isLargeScreen: Flow<Boolean> = _isLargeScreen.asStateFlow()
+
     override val isReverseDefaultRotation = false
 
     fun setIsInRearDisplayMode(isInRearDisplayMode: Boolean) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt
index 77f501f..68ef555 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt
@@ -33,6 +33,10 @@
     override val sensorLocation: StateFlow<Point?>
         get() = faceSensorLocation
 
+    private val currentCameraInfo = MutableStateFlow<CameraInfo?>(null)
+    override val cameraInfo: StateFlow<CameraInfo?>
+        get() = currentCameraInfo
+
     fun setLockoutMode(userId: Int, mode: LockoutMode) {
         lockoutModesForUser[userId] = mode
     }
@@ -47,4 +51,8 @@
     fun setSensorLocation(value: Point?) {
         faceSensorLocation.value = value
     }
+
+    fun setCameraIno(value: CameraInfo?) {
+        currentCameraInfo.value = value
+    }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
index f95c721..005cac4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
@@ -28,7 +28,6 @@
 
 @SysUISingleton
 class FakeFingerprintPropertyRepository @Inject constructor() : FingerprintPropertyRepository {
-    override val propertiesInitialized: MutableStateFlow<Boolean> = MutableStateFlow(false)
 
     private val _sensorId: MutableStateFlow<Int> = MutableStateFlow(-1)
     override val sensorId = _sensorId.asStateFlow()
@@ -51,7 +50,6 @@
         sensorType: FingerprintSensorType,
         sensorLocations: Map<String, SensorLocationInternal>
     ) {
-        propertiesInitialized.value = true
         _sensorId.value = sensorId
         _strength.value = strength
         _sensorType.value = sensorType
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt
index f192de2..c3af437 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt
@@ -1,6 +1,8 @@
 package com.android.systemui.biometrics.data.repository
 
+import android.hardware.biometrics.Flags
 import android.hardware.biometrics.PromptInfo
+import com.android.systemui.biometrics.Utils
 import com.android.systemui.biometrics.shared.model.PromptKind
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.asStateFlow
@@ -26,6 +28,9 @@
     private val _isConfirmationRequired = MutableStateFlow(false)
     override val isConfirmationRequired = _isConfirmationRequired.asStateFlow()
 
+    private val _showBpWithoutIconForCredential = MutableStateFlow(false)
+    override val showBpWithoutIconForCredential = _showBpWithoutIconForCredential.asStateFlow()
+
     private val _opPackageName: MutableStateFlow<String?> = MutableStateFlow(null)
     override val opPackageName = _opPackageName.asStateFlow()
 
@@ -69,6 +74,16 @@
         _isConfirmationRequired.value = false
     }
 
+    override fun setShouldShowBpWithoutIconForCredential(promptInfo: PromptInfo) {
+        val hasCredentialViewShown = kind.value !is PromptKind.Biometric
+        val showBpForCredential =
+            Flags.customBiometricPrompt() &&
+                !Utils.isBiometricAllowed(promptInfo) &&
+                Utils.isDeviceCredentialAllowed(promptInfo) &&
+                promptInfo.contentView != null
+        _showBpWithoutIconForCredential.value = showBpForCredential && !hasCredentialViewShown
+    }
+
     fun setIsShowing(showing: Boolean) {
         _isShowing.value = showing
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/shared/flag/ComposeBouncerFlagsKosmos.kt
similarity index 66%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/shared/flag/ComposeBouncerFlagsKosmos.kt
index b370859..5c3e1f4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/shared/flag/ComposeBouncerFlagsKosmos.kt
@@ -14,14 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyguard.ui.viewmodel
+package com.android.systemui.bouncer.shared.flag
 
-import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+var Kosmos.fakeComposeBouncerFlags by
+    Kosmos.Fixture { FakeComposeBouncerFlags(fakeSceneContainerFlags) }
+val Kosmos.composeBouncerFlags by Kosmos.Fixture<ComposeBouncerFlags> { fakeComposeBouncerFlags }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/shared/flag/FakeComposeBouncerFlags.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/shared/flag/FakeComposeBouncerFlags.kt
new file mode 100644
index 0000000..c116bbd
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/shared/flag/FakeComposeBouncerFlags.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.bouncer.shared.flag
+
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
+
+class FakeComposeBouncerFlags(
+    private val sceneContainerFlags: SceneContainerFlags,
+    var composeBouncerEnabled: Boolean = false
+) : ComposeBouncerFlags {
+    override fun isComposeBouncerOrSceneContainerEnabled(): Boolean {
+        return sceneContainerFlags.isEnabled() || composeBouncerEnabled
+    }
+
+    @Deprecated(
+        "Avoid using this, this is meant to be used only by the glue code " +
+            "that includes compose bouncer in legacy keyguard.",
+        replaceWith = ReplaceWith("isComposeBouncerOrSceneContainerEnabled()")
+    )
+    override fun isOnlyComposeBouncerEnabled(): Boolean = composeBouncerEnabled
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt
index 99dfe94..6d97238 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt
@@ -21,12 +21,12 @@
 import com.android.systemui.bouncer.domain.interactor.bouncerActionButtonInteractor
 import com.android.systemui.bouncer.domain.interactor.bouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.simBouncerInteractor
+import com.android.systemui.bouncer.shared.flag.composeBouncerFlags
 import com.android.systemui.inputmethod.domain.interactor.inputMethodInteractor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
 import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.kosmos.testScope
-import com.android.systemui.scene.shared.flag.sceneContainerFlags
 import com.android.systemui.user.domain.interactor.selectedUserInteractor
 import com.android.systemui.user.ui.viewmodel.userSwitcherViewModel
 import com.android.systemui.util.mockito.mock
@@ -42,7 +42,7 @@
         simBouncerInteractor = simBouncerInteractor,
         authenticationInteractor = authenticationInteractor,
         selectedUserInteractor = selectedUserInteractor,
-        flags = sceneContainerFlags,
+        flags = composeBouncerFlags,
         selectedUser = userSwitcherViewModel.selectedUser,
         users = userSwitcherViewModel.users,
         userSwitcherMenu = userSwitcherViewModel.menu,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/camera/data/repository/FakeCameraAutoRotateRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/camera/data/repository/FakeCameraAutoRotateRepository.kt
new file mode 100644
index 0000000..b8284ac
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/camera/data/repository/FakeCameraAutoRotateRepository.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.camera.data.repository
+
+import android.os.UserHandle
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+class FakeCameraAutoRotateRepository : CameraAutoRotateRepository {
+    private val userMap = mutableMapOf<Int, MutableStateFlow<Boolean>>()
+
+    /** Send a Unit signal when value changes */
+    override fun isCameraAutoRotateSettingEnabled(userHandle: UserHandle): StateFlow<Boolean> =
+        getFlow(userHandle.identifier)
+
+    fun setEnabled(userHandle: UserHandle, enabled: Boolean) {
+        getFlow(userHandle.identifier).value = enabled
+    }
+
+    /** initializes the flow if already not */
+    private fun getFlow(userId: Int): MutableStateFlow<Boolean> =
+        userMap.getOrPut(userId) { MutableStateFlow(false) }
+}
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/camera/data/repository/FakeCameraAutoRotateRepositoryKosmos.kt
similarity index 72%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/camera/data/repository/FakeCameraAutoRotateRepositoryKosmos.kt
index 8ad0a08..615c596 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/camera/data/repository/FakeCameraAutoRotateRepositoryKosmos.kt
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.volume.panel.component.mediaoutput
+package com.android.systemui.camera.data.repository
 
-import dagger.Module
+import com.android.systemui.kosmos.Kosmos
 
-@Module interface MediaOutputModule
+val Kosmos.fakeCameraAutoRotateRepository: FakeCameraAutoRotateRepository by
+    Kosmos.Fixture { FakeCameraAutoRotateRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/camera/data/repository/FakeCameraSensorPrivacyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/camera/data/repository/FakeCameraSensorPrivacyRepository.kt
new file mode 100644
index 0000000..994e9b2
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/camera/data/repository/FakeCameraSensorPrivacyRepository.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.camera.data.repository
+
+import android.os.UserHandle
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+class FakeCameraSensorPrivacyRepository : CameraSensorPrivacyRepository {
+
+    private val userMap = mutableMapOf<Int, MutableStateFlow<Boolean>>()
+    override fun isEnabled(userHandle: UserHandle): StateFlow<Boolean> =
+        getFlow(userHandle.identifier)
+
+    fun setEnabled(userHandle: UserHandle, enabled: Boolean) {
+        getFlow(userHandle.identifier).value = enabled
+    }
+
+    /** initializes the flow if already not */
+    private fun getFlow(userId: Int): MutableStateFlow<Boolean> =
+        userMap.getOrPut(userId) { MutableStateFlow(false) }
+}
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/camera/data/repository/FakeCameraSensorPrivacyRepositoryKosmos.kt
similarity index 71%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/camera/data/repository/FakeCameraSensorPrivacyRepositoryKosmos.kt
index 8ad0a08..c7e704c 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/camera/data/repository/FakeCameraSensorPrivacyRepositoryKosmos.kt
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.volume.panel.component.mediaoutput
+package com.android.systemui.camera.data.repository
 
-import dagger.Module
+import com.android.systemui.kosmos.Kosmos
 
-@Module interface MediaOutputModule
+val Kosmos.fakeCameraSensorPrivacyRepository: FakeCameraSensorPrivacyRepository by
+    Kosmos.Fixture { FakeCameraSensorPrivacyRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java
index 5038285..974a11c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java
@@ -201,4 +201,13 @@
     public List<FalsingTapListener> getTapListeners() {
         return mTapListeners;
     }
+
+    /**
+     * Calls every registered {@link FalsingBeliefListener} as if false touch occurred.
+     */
+    public void sendFalsingBelief() {
+        for (FalsingBeliefListener listener : mFalsingBeliefListeners) {
+            listener.onFalse();
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt
index 9d508d2..5ff588f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalRepository.kt
@@ -1,7 +1,8 @@
 package com.android.systemui.communal.data.repository
 
-import com.android.systemui.communal.shared.model.CommunalSceneKey
-import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
+import com.android.systemui.communal.shared.model.CommunalScenes
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
@@ -16,17 +17,16 @@
 @OptIn(ExperimentalCoroutinesApi::class)
 class FakeCommunalRepository(
     applicationScope: CoroutineScope,
-    override val desiredScene: MutableStateFlow<CommunalSceneKey> =
-        MutableStateFlow(CommunalSceneKey.DEFAULT),
+    override val desiredScene: MutableStateFlow<SceneKey> =
+        MutableStateFlow(CommunalScenes.Default),
 ) : CommunalRepository {
-    override fun setDesiredScene(desiredScene: CommunalSceneKey) {
+    override fun setDesiredScene(desiredScene: SceneKey) {
         this.desiredScene.value = desiredScene
     }
 
-    private val defaultTransitionState =
-        ObservableCommunalTransitionState.Idle(CommunalSceneKey.DEFAULT)
-    private val _transitionState = MutableStateFlow<Flow<ObservableCommunalTransitionState>?>(null)
-    override val transitionState: StateFlow<ObservableCommunalTransitionState> =
+    private val defaultTransitionState = ObservableTransitionState.Idle(CommunalScenes.Default)
+    private val _transitionState = MutableStateFlow<Flow<ObservableTransitionState>?>(null)
+    override val transitionState: StateFlow<ObservableTransitionState> =
         _transitionState
             .flatMapLatest { innerFlowOrNull -> innerFlowOrNull ?: flowOf(defaultTransitionState) }
             .stateIn(
@@ -35,7 +35,7 @@
                 initialValue = defaultTransitionState,
             )
 
-    override fun setTransitionState(transitionState: Flow<ObservableCommunalTransitionState>?) {
+    override fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) {
         _transitionState.value = transitionState
     }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerRule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerRule.kt
index 3faa6eb..4e05de2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerRule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerRule.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.flags
 
 import android.util.Log
-import com.android.systemui.compose.ComposeFacade
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import org.junit.Assert
 import org.junit.Assume
@@ -42,10 +41,6 @@
                         null || description?.getAnnotation(EnableSceneContainer::class.java) != null
                 if (hasAnnotation) {
                     Assume.assumeTrue(
-                        "Compose must be available for @EnableSceneContainer test",
-                        ComposeFacade.isComposeAvailable()
-                    )
-                    Assume.assumeTrue(
                         "Couldn't set Flags.SCENE_CONTAINER_ENABLED for @EnableSceneContainer test",
                         trySetSceneContainerEnabled(true)
                     )
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
index 534f773..592fa38 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt
@@ -45,8 +45,15 @@
     private val _currentClock = MutableStateFlow(null)
     override val currentClock = _currentClock
 
-    private val _previewClock = MutableStateFlow(Mockito.mock(ClockController::class.java))
-    override val previewClock: StateFlow<ClockController> = _previewClock
+    private val _previewClockPair =
+        MutableStateFlow(
+            Pair(
+                Mockito.mock(ClockController::class.java),
+                Mockito.mock(ClockController::class.java)
+            )
+        )
+    override val previewClockPair: StateFlow<Pair<ClockController, ClockController>> =
+        _previewClockPair
     override val clockEventController: ClockEventController
         get() = mock()
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt
index da5cd67..2477415 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.power.domain.interactor.powerInteractor
 
 val Kosmos.fromAodTransitionInteractor by
     Kosmos.Fixture {
@@ -30,5 +31,6 @@
             bgDispatcher = testDispatcher,
             mainDispatcher = testDispatcher,
             keyguardInteractor = keyguardInteractor,
+            powerInteractor = powerInteractor,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt
index 55885bf..5dd5073 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt
@@ -19,13 +19,11 @@
 import com.android.systemui.communal.domain.interactor.communalInteractor
 import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.kosmos.testDispatcher
 
 val Kosmos.glanceableHubTransitions by
     Kosmos.Fixture {
         GlanceableHubTransitions(
-            scope = applicationCoroutineScope,
             bgDispatcher = testDispatcher,
             transitionRepository = keyguardTransitionRepository,
             transitionInteractor = keyguardTransitionInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelKosmos.kt
similarity index 62%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelKosmos.kt
index b370859..c6f0706 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelKosmos.kt
@@ -16,12 +16,16 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+@ExperimentalCoroutinesApi
+val Kosmos.alternateBouncerToDozingTransitionViewModel by Fixture {
+    AlternateBouncerToDozingTransitionViewModel(
+        deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
+        animationFlow = keyguardTransitionAnimationFlow,
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt
index 9fe6571..73fd999 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor
 import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
 import com.android.systemui.deviceentry.domain.interactor.deviceEntrySourceInteractor
 import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
@@ -51,6 +50,5 @@
         keyguardViewController = { statusBarKeyguardViewManager },
         deviceEntryInteractor = deviceEntryInteractor,
         deviceEntrySourceInteractor = deviceEntrySourceInteractor,
-        fingerprintPropertyInteractor = fingerprintPropertyInteractor,
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelKosmos.kt
similarity index 73%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelKosmos.kt
index b370859..36ddc29 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelKosmos.kt
@@ -18,10 +18,12 @@
 
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+@ExperimentalCoroutinesApi
+val Kosmos.dozingToGoneTransitionViewModel by Fixture {
+    DozingToGoneTransitionViewModel(
+        animationFlow = keyguardTransitionAnimationFlow,
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt
index 400a0d8..de52d84 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-@file:OptIn(ExperimentalCoroutinesApi::class)
-
 package com.android.systemui.keyguard.ui.viewmodel
 
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
@@ -23,6 +21,7 @@
 import com.android.systemui.kosmos.Kosmos.Fixture
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
+@ExperimentalCoroutinesApi
 val Kosmos.dozingToLockscreenTransitionViewModel by Fixture {
     DozingToLockscreenTransitionViewModel(
         animationFlow = keyguardTransitionAnimationFlow,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelKosmos.kt
similarity index 71%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelKosmos.kt
index b370859..dc6b26f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelKosmos.kt
@@ -18,10 +18,12 @@
 
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+@ExperimentalCoroutinesApi
+val Kosmos.dozingToPrimaryBouncerTransitionViewModel by Fixture {
+    DozingToPrimaryBouncerTransitionViewModel(
+        animationFlow = keyguardTransitionAnimationFlow,
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelKosmos.kt
similarity index 87%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelKosmos.kt
index b370859..00741eb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelKosmos.kt
@@ -16,12 +16,14 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import com.android.systemui.common.ui.domain.interactor.configurationInteractor
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
 
 val Kosmos.dreamingToGlanceableHubTransitionViewModel by
     Kosmos.Fixture {
         DreamingToGlanceableHubTransitionViewModel(
+            configurationInteractor = configurationInteractor,
             animationFlow = keyguardTransitionAnimationFlow,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt
index 8b5407c..5f70a2f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt
@@ -14,11 +14,8 @@
  * limitations under the License.
  */
 
-@file:OptIn(ExperimentalCoroutinesApi::class)
-
 package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
@@ -26,11 +23,11 @@
 import com.android.systemui.util.mockito.mock
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
+@ExperimentalCoroutinesApi
 val Kosmos.dreamingToLockscreenTransitionViewModel by Fixture {
     DreamingToLockscreenTransitionViewModel(
         keyguardTransitionInteractor = keyguardTransitionInteractor,
         fromDreamingTransitionInteractor = mock(),
-        deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
         animationFlow = keyguardTransitionAnimationFlow,
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelKosmos.kt
similarity index 77%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelKosmos.kt
index b370859..1302f15 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelKosmos.kt
@@ -16,12 +16,14 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import com.android.systemui.common.ui.domain.interactor.configurationInteractor
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
+val Kosmos.glanceableHubToDreamingTransitionViewModel by
     Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
+        GlanceableHubToDreamingTransitionViewModel(
+            configurationInteractor = configurationInteractor,
             animationFlow = keyguardTransitionAnimationFlow,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt
index 4daf460..b19d4e8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt
@@ -14,17 +14,18 @@
  * limitations under the License.
  */
 
-@file:OptIn(ExperimentalCoroutinesApi::class)
-
 package com.android.systemui.keyguard.ui.viewmodel
 
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
+@ExperimentalCoroutinesApi
 val Kosmos.goneToDozingTransitionViewModel by Fixture {
     GoneToDozingTransitionViewModel(
+        deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
         animationFlow = keyguardTransitionAnimationFlow,
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
index ecf66a2..c2300a1e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
@@ -39,9 +39,16 @@
         keyguardTransitionInteractor = keyguardTransitionInteractor,
         notificationsKeyguardInteractor = notificationsKeyguardInteractor,
         alternateBouncerToGoneTransitionViewModel = alternateBouncerToGoneTransitionViewModel,
+        aodToGoneTransitionViewModel = aodToGoneTransitionViewModel,
         aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel,
+        dozingToGoneTransitionViewModel = dozingToGoneTransitionViewModel,
         dozingToLockscreenTransitionViewModel = dozingToLockscreenTransitionViewModel,
+        dreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel,
         glanceableHubToLockscreenTransitionViewModel = glanceableHubToLockscreenTransitionViewModel,
+        goneToAodTransitionViewModel = goneToAodTransitionViewModel,
+        goneToDozingTransitionViewModel = goneToDozingTransitionViewModel,
+        lockscreenToAodTransitionViewModel = lockscreenToAodTransitionViewModel,
+        lockscreenToDozingTransitionViewModel = lockscreenToDozingTransitionViewModel,
         lockscreenToDreamingTransitionViewModel = lockscreenToDreamingTransitionViewModel,
         lockscreenToGlanceableHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel,
         lockscreenToGoneTransitionViewModel = lockscreenToGoneTransitionViewModel,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt
index 96de4ba..8da5dd4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelKosmos.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.keyguard.domain.interactor.keyguardBlueprintInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.policy.splitShadeStateController
 
 val Kosmos.lockscreenContentViewModel by
     Kosmos.Fixture {
@@ -28,5 +29,6 @@
             interactor = keyguardBlueprintInteractor,
             authController = authController,
             longPress = keyguardLongPressViewModel,
+            splitShadeStateController = splitShadeStateController,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelKosmos.kt
similarity index 63%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelKosmos.kt
index b370859..aa8e9a8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelKosmos.kt
@@ -16,12 +16,16 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+@ExperimentalCoroutinesApi
+val Kosmos.lockscreenToDozingTransitionViewModel by Fixture {
+    LockscreenToDozingTransitionViewModel(
+        deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
+        animationFlow = keyguardTransitionAnimationFlow,
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt
index 1b2337f..17c3a14 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-@file:OptIn(ExperimentalCoroutinesApi::class)
-
 package com.android.systemui.keyguard.ui.viewmodel
 
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
@@ -23,6 +21,7 @@
 import com.android.systemui.kosmos.Kosmos.Fixture
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
+@ExperimentalCoroutinesApi
 val Kosmos.lockscreenToGoneTransitionViewModel by Fixture {
     LockscreenToGoneTransitionViewModel(
         animationFlow = keyguardTransitionAnimationFlow,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelKosmos.kt
similarity index 63%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelKosmos.kt
index b370859..d4e4b8c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelKosmos.kt
@@ -16,12 +16,16 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+@ExperimentalCoroutinesApi
+val Kosmos.primaryBouncerToDozingTransitionViewModel by Fixture {
+    PrimaryBouncerToDozingTransitionViewModel(
+        deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
+        animationFlow = keyguardTransitionAnimationFlow,
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/SpatializerKosmos.kt
similarity index 63%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/media/SpatializerKosmos.kt
index b370859..7001ea8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/SpatializerKosmos.kt
@@ -14,14 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyguard.ui.viewmodel
+package com.android.systemui.media
 
-import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
+import com.android.settingslib.media.domain.interactor.SpatializerInteractor
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.media.data.repository.FakeSpatializerRepository
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+val Kosmos.spatializerRepository by Kosmos.Fixture { FakeSpatializerRepository() }
+val Kosmos.spatializerInteractor by Kosmos.Fixture { SpatializerInteractor(spatializerRepository) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/data/repository/FakeSpatializerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/data/repository/FakeSpatializerRepository.kt
new file mode 100644
index 0000000..0183b97
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/data/repository/FakeSpatializerRepository.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.data.repository
+
+import android.media.AudioDeviceAttributes
+import com.android.settingslib.media.data.repository.SpatializerRepository
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeSpatializerRepository : SpatializerRepository {
+
+    var defaultSpatialAudioAvailable: Boolean = false
+
+    private val spatialAudioAvailabilityByDevice: MutableMap<AudioDeviceAttributes, Boolean> =
+        mutableMapOf()
+    private val spatialAudioCompatibleDevices: MutableList<AudioDeviceAttributes> = mutableListOf()
+
+    private val mutableHeadTrackingAvailable = MutableStateFlow(false)
+    private val headTrackingEnabledByDevice = mutableMapOf<AudioDeviceAttributes, Boolean>()
+
+    override val isHeadTrackingAvailable: StateFlow<Boolean> =
+        mutableHeadTrackingAvailable.asStateFlow()
+
+    override suspend fun isSpatialAudioAvailableForDevice(
+        audioDeviceAttributes: AudioDeviceAttributes
+    ): Boolean =
+        spatialAudioAvailabilityByDevice.getOrDefault(
+            audioDeviceAttributes,
+            defaultSpatialAudioAvailable
+        )
+
+    override suspend fun getSpatialAudioCompatibleDevices(): Collection<AudioDeviceAttributes> =
+        spatialAudioCompatibleDevices
+
+    override suspend fun addSpatialAudioCompatibleDevice(
+        audioDeviceAttributes: AudioDeviceAttributes
+    ) {
+        spatialAudioCompatibleDevices.add(audioDeviceAttributes)
+    }
+
+    override suspend fun removeSpatialAudioCompatibleDevice(
+        audioDeviceAttributes: AudioDeviceAttributes
+    ) {
+        spatialAudioCompatibleDevices.remove(audioDeviceAttributes)
+    }
+
+    override suspend fun isHeadTrackingEnabled(
+        audioDeviceAttributes: AudioDeviceAttributes
+    ): Boolean = headTrackingEnabledByDevice.getOrDefault(audioDeviceAttributes, false)
+
+    override suspend fun setHeadTrackingEnabled(
+        audioDeviceAttributes: AudioDeviceAttributes,
+        isEnabled: Boolean
+    ) {
+        headTrackingEnabledByDevice[audioDeviceAttributes] = isEnabled
+    }
+
+    fun setIsSpatialAudioAvailable(
+        audioDeviceAttributes: AudioDeviceAttributes,
+        isAvailable: Boolean,
+    ) {
+        spatialAudioAvailabilityByDevice[audioDeviceAttributes] = isAvailable
+    }
+
+    fun setIsHeadTrackingAvailable(isAvailable: Boolean) {
+        mutableHeadTrackingAvailable.value = isAvailable
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/rotation/RotationLockTileKosmos.kt
similarity index 66%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/rotation/RotationLockTileKosmos.kt
index b370859..ecf8ce5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/rotation/RotationLockTileKosmos.kt
@@ -14,14 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyguard.ui.viewmodel
+package com.android.systemui.qs.tiles.impl.rotation
 
-import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.qsEventLogger
+import com.android.systemui.rotationlock.RotationLockNewModule
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+val Kosmos.qsRotationLockTileConfig by
+    Kosmos.Fixture { RotationLockNewModule.provideRotationTileConfig(qsEventLogger) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
index 8fc419c..2cdf76d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
@@ -3,18 +3,18 @@
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
 import com.android.systemui.scene.shared.model.SceneContainerConfig
-import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.Scenes
 
 var Kosmos.sceneKeys by Fixture {
     listOf(
-        SceneKey.QuickSettings,
-        SceneKey.Shade,
-        SceneKey.Lockscreen,
-        SceneKey.Bouncer,
-        SceneKey.Gone,
-        SceneKey.Communal,
+        Scenes.QuickSettings,
+        Scenes.Shade,
+        Scenes.Lockscreen,
+        Scenes.Bouncer,
+        Scenes.Gone,
+        Scenes.Communal,
     )
 }
 
-val Kosmos.initialSceneKey by Fixture { SceneKey.Lockscreen }
+val Kosmos.initialSceneKey by Fixture { Scenes.Lockscreen }
 val Kosmos.sceneContainerConfig by Fixture { SceneContainerConfig(sceneKeys, initialSceneKey) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt
index c208aad..59a01cb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.scene.shared.model
 
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.TransitionKey
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorKosmos.kt
new file mode 100644
index 0000000..db6ba62
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackInteractorKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.stack.domain.interactor
+
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.power.domain.interactor.powerInteractor
+
+val Kosmos.notificationStackInteractor by Fixture {
+    NotificationStackInteractor(
+        keyguardInteractor = keyguardInteractor,
+        powerInteractor = powerInteractor,
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
index 25e3eac..f1767eb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
@@ -16,16 +16,15 @@
 
 package com.android.systemui.statusbar.notification.stack.ui.viewmodel
 
-import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
-import com.android.systemui.power.domain.interactor.powerInteractor
 import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.statusbar.domain.interactor.remoteInputInteractor
 import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
 import com.android.systemui.statusbar.notification.domain.interactor.seenNotificationsInteractor
 import com.android.systemui.statusbar.notification.footer.ui.viewmodel.footerViewModel
 import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.notificationShelfViewModel
+import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationStackInteractor
 import com.android.systemui.statusbar.policy.domain.interactor.userSetupInteractor
 import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor
 import java.util.Optional
@@ -37,8 +36,7 @@
         Optional.of(footerViewModel),
         Optional.of(notificationListLoggerViewModel),
         activeNotificationsInteractor,
-        keyguardInteractor,
-        powerInteractor,
+        notificationStackInteractor,
         remoteInputInteractor,
         seenNotificationsInteractor,
         shadeInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModelKosmos.kt
index d79633a..bada2a6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModelKosmos.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.stack.ui.viewmodel
 
+import com.android.systemui.dump.dumpManager
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
 import com.android.systemui.scene.domain.interactor.sceneInteractor
@@ -24,6 +25,7 @@
 
 val Kosmos.notificationStackAppearanceViewModel by Fixture {
     NotificationStackAppearanceViewModel(
+        dumpManager = dumpManager,
         stackAppearanceInteractor = notificationStackAppearanceInteractor,
         shadeInteractor = shadeInteractor,
         sceneInteractor = sceneInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/PanelExpansionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/PanelExpansionInteractorKosmos.kt
new file mode 100644
index 0000000..a025846
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/PanelExpansionInteractorKosmos.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.stack.ui.viewmodel
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.scene.domain.interactor.PanelExpansionInteractor
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.shade.data.repository.shadeRepository
+
+val Kosmos.panelExpansionInteractor by Fixture {
+    PanelExpansionInteractor(
+        sceneInteractor = sceneInteractor,
+        shadeRepository = shadeRepository,
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
index 832344d..106e85c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.notification.stack.ui.viewmodel
 
 import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.dump.dumpManager
 import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
 import com.android.systemui.keyguard.ui.viewmodel.alternateBouncerToGoneTransitionViewModel
@@ -48,6 +49,7 @@
 val Kosmos.sharedNotificationContainerViewModel by Fixture {
     SharedNotificationContainerViewModel(
         interactor = sharedNotificationContainerInteractor,
+        dumpManager = dumpManager,
         applicationScope = applicationCoroutineScope,
         keyguardInteractor = keyguardInteractor,
         keyguardTransitionInteractor = keyguardTransitionInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
index 41c11ad6..7a86c4f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
@@ -33,6 +33,7 @@
 import com.android.systemui.shade.domain.interactor.shadeAnimationInteractor
 import com.android.systemui.shade.shadeController
 import com.android.systemui.shade.shadeViewController
+import com.android.systemui.statusbar.commandQueue
 import com.android.systemui.statusbar.notification.collection.provider.launchFullScreenIntentProvider
 import com.android.systemui.statusbar.notification.collection.render.notificationVisibilityProvider
 import com.android.systemui.statusbar.notification.notificationTransitionAnimatorControllerProvider
@@ -59,6 +60,7 @@
             notificationVisibilityProvider,
             headsUpManager,
             activityStarter,
+            commandQueue,
             notificationClickNotifier,
             statusBarKeyguardViewManager,
             keyguardManager,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
index c010327..11acf1c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
@@ -60,6 +60,8 @@
 
     override val isInService = MutableStateFlow(true)
 
+    override val isEmergencyOnly = MutableStateFlow(true)
+
     override val isNonTerrestrial = MutableStateFlow(false)
 
     private val _isDataEnabled = MutableStateFlow(true)
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/DevicePostureControllerKosmos.kt
similarity index 72%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/DevicePostureControllerKosmos.kt
index 8ad0a08..89eaf15 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/DevicePostureControllerKosmos.kt
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.volume.panel.component.mediaoutput
+package com.android.systemui.statusbar.policy
 
-import dagger.Module
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
 
-@Module interface MediaOutputModule
+val Kosmos.devicePostureController by Kosmos.Fixture { mock<DevicePostureController>() }
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettingsKosmos.kt
similarity index 73%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettingsKosmos.kt
index 8ad0a08..df6fc41 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettingsKosmos.kt
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.volume.panel.component.mediaoutput
+package com.android.systemui.util.settings
 
-import dagger.Module
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
 
-@Module interface MediaOutputModule
+val Kosmos.fakeGlobalSettings: FakeGlobalSettings by Fixture { FakeGlobalSettings() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeRotationLockController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeRotationLockController.java
index be57658..4aa85a7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeRotationLockController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeRotationLockController.java
@@ -19,13 +19,29 @@
 import com.android.systemui.statusbar.policy.RotationLockController;
 import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class FakeRotationLockController extends BaseLeakChecker<RotationLockControllerCallback>
         implements RotationLockController {
+    private boolean mIsLocked = false;
+    private final List<RotationLockControllerCallback> mCallbacks = new ArrayList<>();
     public FakeRotationLockController(LeakCheck test) {
         super(test, "rotation");
     }
 
     @Override
+    public void addCallback(RotationLockControllerCallback listener) {
+        mCallbacks.add(listener);
+        listener.onRotationLockStateChanged(mIsLocked, isRotationLockAffordanceVisible());
+    }
+
+    @Override
+    public void removeCallback(RotationLockControllerCallback listener) {
+        mCallbacks.remove(listener);
+    }
+
+    @Override
     public void setListening(boolean listening) {
 
     }
@@ -42,12 +58,15 @@
 
     @Override
     public boolean isRotationLocked() {
-        return false;
+        return mIsLocked;
     }
 
     @Override
     public void setRotationLocked(boolean locked, String caller) {
-
+        mIsLocked = locked;
+        for (RotationLockControllerCallback callback : mCallbacks) {
+            callback.onRotationLockStateChanged(locked, isRotationLockAffordanceVisible());
+        }
     }
 
     @Override
diff --git a/proto/src/criticalevents/critical_event_log.proto b/proto/src/criticalevents/critical_event_log.proto
index cffcd09..71d291a 100644
--- a/proto/src/criticalevents/critical_event_log.proto
+++ b/proto/src/criticalevents/critical_event_log.proto
@@ -61,6 +61,12 @@
     NativeCrash native_crash = 6;
     SystemServerStarted system_server_started = 7;
     InstallPackages install_packages = 8;
+    ExcessiveBinderCalls excessive_binder_calls = 9;
+  }
+
+  message ExcessiveBinderCalls {
+    // The uid sending many calls.
+    optional int32 uid = 1;
   }
 
   message InstallPackages {}
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 53897e1..178102e 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -47,6 +47,7 @@
     ],
     libs: [
         "framework-minus-apex.ravenwood",
+        "ravenwood-junit",
     ],
     visibility: ["//visibility:private"],
 }
@@ -76,6 +77,7 @@
     libs: [
         "android.test.mock",
         "framework-minus-apex.ravenwood",
+        "ravenwood-framework",
         "services.core.ravenwood",
         "junit",
     ],
@@ -84,6 +86,21 @@
     jarjar_rules: ":ravenwood-services-jarjar-rules",
 }
 
+// Separated out from ravenwood-junit-impl since it needs to compile
+// against `module_current`
+java_library {
+    name: "ravenwood-junit-impl-flag",
+    srcs: [
+        "junit-flag-src/**/*.java",
+    ],
+    sdk_version: "module_current",
+    libs: [
+        "junit",
+        "flag-junit",
+    ],
+    visibility: ["//visibility:public"],
+}
+
 // Carefully compiles against only test_current to support tests that
 // want to verify they're unbundled.  The "impl" library above is what
 // ships inside the Ravenwood environment to actually drive any API
@@ -93,14 +110,31 @@
     srcs: [
         "junit-src/**/*.java",
         "junit-stub-src/**/*.java",
+        "junit-flag-src/**/*.java",
     ],
     sdk_version: "test_current",
     libs: [
         "junit",
+        "flag-junit",
     ],
     visibility: ["//visibility:public"],
 }
 
+// Library used to publish a handful of `android.ravenwood` APIs into
+// the Ravenwood BCP; we don't want to publish these APIs into the BCP
+// on physical devices, which is why this is a separate library
+java_library {
+    name: "ravenwood-framework",
+    srcs: [
+        "framework-src/**/*.java",
+    ],
+    libs: [
+        "framework-minus-apex.ravenwood",
+    ],
+    sdk_version: "core_current",
+    visibility: ["//visibility:public"],
+}
+
 java_host_for_device {
     name: "androidx.test.monitor-for-device",
     libs: [
diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/framework-minus-apex-ravenwood-policies.txt
index 6b67364..371c3ac 100644
--- a/ravenwood/framework-minus-apex-ravenwood-policies.txt
+++ b/ravenwood/framework-minus-apex-ravenwood-policies.txt
@@ -55,3 +55,5 @@
     method getSystemService (Ljava/lang/Class;)Ljava/lang/Object; stub
 class android.content.pm.PackageManager stub
     method <init> ()V stub
+class android.text.ClipboardManager stub
+    method <init> ()V stub
diff --git a/ravenwood/framework-src/android/ravenwood/example/BlueManager.java b/ravenwood/framework-src/android/ravenwood/example/BlueManager.java
new file mode 100644
index 0000000..fc713b1
--- /dev/null
+++ b/ravenwood/framework-src/android/ravenwood/example/BlueManager.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.ravenwood.example;
+
+import android.annotation.SystemService;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+@SystemService(BlueManager.SERVICE_NAME)
+public class BlueManager {
+    public static final String SERVICE_NAME = "example_blue";
+
+    public String getInterfaceDescriptor() {
+        try {
+            return ServiceManager.getService(SERVICE_NAME).getInterfaceDescriptor();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/ravenwood/framework-src/android/ravenwood/example/RedManager.java b/ravenwood/framework-src/android/ravenwood/example/RedManager.java
new file mode 100644
index 0000000..381a901
--- /dev/null
+++ b/ravenwood/framework-src/android/ravenwood/example/RedManager.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.ravenwood.example;
+
+import android.annotation.SystemService;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+@SystemService(RedManager.SERVICE_NAME)
+public class RedManager {
+    public static final String SERVICE_NAME = "example_red";
+
+    public String getInterfaceDescriptor() {
+        try {
+            return ServiceManager.getService(SERVICE_NAME).getInterfaceDescriptor();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/ravenwood/junit-flag-src/android/platform/test/flag/junit/RavenwoodFlagsValueProvider.java b/ravenwood/junit-flag-src/android/platform/test/flag/junit/RavenwoodFlagsValueProvider.java
new file mode 100644
index 0000000..9d62774
--- /dev/null
+++ b/ravenwood/junit-flag-src/android/platform/test/flag/junit/RavenwoodFlagsValueProvider.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.platform.test.flag.junit;
+
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.IFlagsValueProvider;
+
+/**
+ * Offer to create {@link CheckFlagsRule} instances that are useful on the Ravenwood deviceless
+ * testing environment.
+ *
+ * At the moment, default flag values are not available on Ravenwood, so the only options offered
+ * here are "all-on" and "all-off" options. Tests that want to exercise specific flag states should
+ * use {@link android.platform.test.flag.junit.SetFlagsRule}.
+ */
+public class RavenwoodFlagsValueProvider {
+    /**
+     * Create a {@link CheckFlagsRule} instance where flags are in an "all-on" state.
+     */
+    public static CheckFlagsRule createAllOnCheckFlagsRule() {
+        return new CheckFlagsRule(new IFlagsValueProvider() {
+            @Override
+            public boolean getBoolean(String flag) {
+                return true;
+            }
+        });
+    }
+
+    /**
+     * Create a {@link CheckFlagsRule} instance where flags are in an "all-off" state.
+     */
+    public static CheckFlagsRule createAllOffCheckFlagsRule() {
+        return new CheckFlagsRule(new IFlagsValueProvider() {
+            @Override
+            public boolean getBoolean(String flag) {
+                return false;
+            }
+        });
+    }
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
index 3668b03..109ef76 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
@@ -16,18 +16,30 @@
 
 package android.platform.test.ravenwood;
 
+import android.content.ClipboardManager;
 import android.content.Context;
 import android.hardware.ISerialManager;
 import android.hardware.SerialManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
 import android.os.PermissionEnforcer;
 import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.ravenwood.example.BlueManager;
+import android.ravenwood.example.RedManager;
 import android.test.mock.MockContext;
 import android.util.ArrayMap;
 import android.util.Singleton;
 
+import java.util.Objects;
+import java.util.concurrent.Executor;
 import java.util.function.Supplier;
 
 public class RavenwoodContext extends MockContext {
+    private final String mPackageName;
+    private final HandlerThread mMainThread;
+
     private final RavenwoodPermissionEnforcer mEnforcer = new RavenwoodPermissionEnforcer();
 
     private final ArrayMap<Class<?>, String> mClassToName = new ArrayMap<>();
@@ -39,14 +51,27 @@
         mNameToFactory.put(serviceName, serviceSupplier);
     }
 
-    public RavenwoodContext() {
+    public RavenwoodContext(String packageName, HandlerThread mainThread) {
+        mPackageName = packageName;
+        mMainThread = mainThread;
+
+        // Services provided by a typical shipping device
+        registerService(ClipboardManager.class,
+                Context.CLIPBOARD_SERVICE, memoize(() ->
+                        new ClipboardManager(this, getMainThreadHandler())));
         registerService(PermissionEnforcer.class,
                 Context.PERMISSION_ENFORCER_SERVICE, () -> mEnforcer);
         registerService(SerialManager.class,
-                Context.SERIAL_SERVICE, asSingleton(() ->
+                Context.SERIAL_SERVICE, memoize(() ->
                         new SerialManager(this, ISerialManager.Stub.asInterface(
                                 ServiceManager.getService(Context.SERIAL_SERVICE)))
                 ));
+
+        // Additional services we provide for testing purposes
+        registerService(BlueManager.class,
+                BlueManager.SERVICE_NAME, memoize(() -> new BlueManager()));
+        registerService(RedManager.class,
+                RedManager.SERVICE_NAME, memoize(() -> new RedManager()));
     }
 
     @Override
@@ -73,18 +98,82 @@
         }
     }
 
+    @Override
+    public Looper getMainLooper() {
+        Objects.requireNonNull(mMainThread,
+                "Test must request setProvideMainThread() via RavenwoodRule");
+        return mMainThread.getLooper();
+    }
+
+    @Override
+    public Handler getMainThreadHandler() {
+        Objects.requireNonNull(mMainThread,
+                "Test must request setProvideMainThread() via RavenwoodRule");
+        return mMainThread.getThreadHandler();
+    }
+
+    @Override
+    public Executor getMainExecutor() {
+        Objects.requireNonNull(mMainThread,
+                "Test must request setProvideMainThread() via RavenwoodRule");
+        return mMainThread.getThreadExecutor();
+    }
+
+    @Override
+    public String getPackageName() {
+        return Objects.requireNonNull(mPackageName,
+                "Test must request setPackageName() via RavenwoodRule");
+    }
+
+    @Override
+    public String getOpPackageName() {
+        return Objects.requireNonNull(mPackageName,
+                "Test must request setPackageName() via RavenwoodRule");
+    }
+
+    @Override
+    public String getAttributionTag() {
+        return null;
+    }
+
+    @Override
+    public UserHandle getUser() {
+        return android.os.UserHandle.of(android.os.UserHandle.myUserId());
+    }
+
+    @Override
+    public int getUserId() {
+        return android.os.UserHandle.myUserId();
+    }
+
+    @Override
+    public int getDeviceId() {
+        return Context.DEVICE_ID_DEFAULT;
+    }
+
     /**
-     * Wrap the given {@link Supplier} to become a memoized singleton.
+     * Wrap the given {@link Supplier} to become memoized.
+     *
+     * The underlying {@link Supplier} will only be invoked once, and that result will be cached
+     * and returned for any future requests.
      */
-    private static <T> Supplier<T> asSingleton(Supplier<T> supplier) {
+    private static <T> Supplier<T> memoize(ThrowingSupplier<T> supplier) {
         final Singleton<T> singleton = new Singleton<>() {
             @Override
             protected T create() {
-                return supplier.get();
+                try {
+                    return supplier.get();
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
             }
         };
         return () -> {
             return singleton.get();
         };
     }
+
+    public interface ThrowingSupplier<T> {
+        T get() throws Exception;
+    }
 }
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index 231cce9..56a3c64 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -110,13 +110,16 @@
 
         ActivityManager.init$ravenwood(rule.mCurrentUser);
 
+        final HandlerThread main;
         if (rule.mProvideMainThread) {
-            final HandlerThread main = new HandlerThread(MAIN_THREAD_NAME);
+            main = new HandlerThread(MAIN_THREAD_NAME);
             main.start();
             Looper.setMainLooperForTest(main.getLooper());
+        } else {
+            main = null;
         }
 
-        rule.mContext = new RavenwoodContext();
+        rule.mContext = new RavenwoodContext(rule.mPackageName, main);
         rule.mInstrumentation = new Instrumentation();
         rule.mInstrumentation.basicInit(rule.mContext);
         InstrumentationRegistry.registerInstance(rule.mInstrumentation, Bundle.EMPTY);
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
index bb280f4..cd6b61d 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
@@ -16,15 +16,22 @@
 
 package android.platform.test.ravenwood;
 
+import android.content.ClipboardManager;
 import android.hardware.SerialManager;
 import android.os.SystemClock;
+import android.ravenwood.example.BlueManager;
+import android.ravenwood.example.RedManager;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
 import com.android.server.utils.TimingsTraceAndSlog;
 
+import java.util.List;
+import java.util.Set;
+
 public class RavenwoodSystemServer {
     /**
      * Set of services that we know how to provide under Ravenwood. We keep this set distinct
@@ -36,13 +43,21 @@
      */
     private static final ArrayMap<Class<?>, String> sKnownServices = new ArrayMap<>();
 
-    // TODO: expand SystemService API to support dependency expression, so we don't need test
-    // authors to exhaustively declare all transitive services
-
     static {
-        sKnownServices.put(SerialManager.class, "com.android.server.SerialService$Lifecycle");
+        // Services provided by a typical shipping device
+        sKnownServices.put(ClipboardManager.class,
+                "com.android.server.FakeClipboardService$Lifecycle");
+        sKnownServices.put(SerialManager.class,
+                "com.android.server.SerialService$Lifecycle");
+
+        // Additional services we provide for testing purposes
+        sKnownServices.put(BlueManager.class,
+                "com.android.server.example.BlueManagerService$Lifecycle");
+        sKnownServices.put(RedManager.class,
+                "com.android.server.example.RedManagerService$Lifecycle");
     }
 
+    private static Set<Class<?>> sStartedServices;
     private static TimingsTraceAndSlog sTimings;
     private static SystemServiceManager sServiceManager;
 
@@ -50,6 +65,7 @@
         // Avoid overhead if no services required
         if (rule.mServicesRequired.isEmpty()) return;
 
+        sStartedServices = new ArraySet<>();
         sTimings = new TimingsTraceAndSlog();
         sServiceManager = new SystemServiceManager(rule.mContext);
         sServiceManager.setStartInfo(false,
@@ -57,17 +73,7 @@
                 SystemClock.uptimeMillis());
         LocalServices.addService(SystemServiceManager.class, sServiceManager);
 
-        for (Class<?> service : rule.mServicesRequired) {
-            final String target = sKnownServices.get(service);
-            if (target == null) {
-                throw new RuntimeException("The requested service " + service
-                        + " is not yet supported under the Ravenwood deviceless testing "
-                        + "environment; consider requesting support from the API owner or "
-                        + "consider using Mockito; more details at go/ravenwood-docs");
-            } else {
-                sServiceManager.startService(target);
-            }
-        }
+        startServices(rule.mServicesRequired);
         sServiceManager.sealStartedServices();
 
         // TODO: expand to include additional boot phases when relevant
@@ -81,5 +87,26 @@
         LocalServices.removeServiceForTest(SystemServiceManager.class);
         sServiceManager = null;
         sTimings = null;
+        sStartedServices = null;
+    }
+
+    private static void startServices(List<Class<?>> serviceClasses) {
+        for (Class<?> serviceClass : serviceClasses) {
+            // Quietly ignore duplicate requests if service already started
+            if (sStartedServices.contains(serviceClass)) continue;
+            sStartedServices.add(serviceClass);
+
+            final String serviceName = sKnownServices.get(serviceClass);
+            if (serviceName == null) {
+                throw new RuntimeException("The requested service " + serviceClass
+                        + " is not yet supported under the Ravenwood deviceless testing "
+                        + "environment; consider requesting support from the API owner or "
+                        + "consider using Mockito; more details at go/ravenwood-docs");
+            }
+
+            // Start service and then depth-first traversal of any dependencies
+            final SystemService instance = sServiceManager.startService(serviceName);
+            startServices(instance.getDependencies());
+        }
     }
 }
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index a8c24fc..52ea340 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -35,6 +35,8 @@
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.regex.Pattern;
@@ -121,11 +123,13 @@
     int mUid = NOBODY_UID;
     int mPid = sNextPid.getAndIncrement();
 
+    String mPackageName;
+
     boolean mProvideMainThread = false;
 
     final RavenwoodSystemProperties mSystemProperties = new RavenwoodSystemProperties();
 
-    final ArraySet<Class<?>> mServicesRequired = new ArraySet<>();
+    final List<Class<?>> mServicesRequired = new ArrayList<>();
 
     volatile Context mContext;
     volatile Instrumentation mInstrumentation;
@@ -158,6 +162,15 @@
         }
 
         /**
+         * Configure the identity of this process to be the given package name for the duration
+         * of the test. Has no effect on non-Ravenwood environments.
+         */
+        public Builder setPackageName(/* @NonNull */ String packageName) {
+            mRule.mPackageName = Objects.requireNonNull(packageName);
+            return this;
+        }
+
+        /**
          * Configure a "main" thread to be available for the duration of the test, as defined
          * by {@code Looper.getMainLooper()}. Has no effect on non-Ravenwood environments.
          */
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java
index b736a76..37ceac6 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java
@@ -73,9 +73,9 @@
                     return;
                 }
             }
-            throw new UnsatisfiedLinkError("Library " + libname + " no found in "
+            throw new UnsatisfiedLinkError("Library " + libname + " not found in "
                     + "java.library.path: " + path);
-        } catch (Exception e) {
+        } catch (Throwable e) {
             dumpFiles(System.out);
             throw e;
         }
@@ -96,6 +96,10 @@
                     listFiles(out, gparent, "");
                 }
             }
+
+            var gparent = new File("../..").getCanonicalFile();
+            out.println("# ../..=" + gparent);
+            listFiles(out, gparent, "");
         } catch (Throwable th) {
             out.println("Error: " + th.toString());
             th.printStackTrace(out);
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index eb3c55c..9b4d378 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -186,6 +186,7 @@
 android.content.ClipData
 android.content.ClipData$Item
 android.content.ClipDescription
+android.content.ClipboardManager
 android.content.ComponentName
 android.content.ContentUris
 android.content.ContentValues
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java
index 5930a14..f301b9c 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java
@@ -22,6 +22,13 @@
 
 import java.io.PrintStream;
 
+/**
+ * Ravenwood "native substitution" class for {@link android.util.Log}.
+ *
+ * {@link android.util.Log} already uses the actual native code and doesn't use this class.
+ * In order to switch to this Java implementation, uncomment the @RavenwoodNativeSubstitutionClass
+ * annotation on {@link android.util.Log}.
+ */
 public class Log_host {
 
     public static boolean isLoggable(String tag, @Level int level) {
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
index 1e12030..cc94090 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
@@ -15,8 +15,9 @@
  */
 package com.android.platform.test.ravenwood.runtimehelper;
 
+import android.platform.test.ravenwood.RavenwoodUtils;
+
 import java.io.File;
-import java.io.PrintStream;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 
@@ -27,8 +28,6 @@
  * load other JNI or do other set up here.
  */
 public class ClassLoadHook {
-    private static PrintStream sOut = System.out;
-
     /**
      * If true, we won't load `libandroid_runtime`
      *
@@ -36,7 +35,7 @@
      * so we need a way to remove the dependency.
      */
     private static final boolean SKIP_LOADING_LIBANDROID = "1".equals(System.getenv(
-            "HOSTTEST_SKIP_LOADING_LIBANDROID"));
+            "RAVENWOOD_SKIP_LOADING_LIBANDROID"));
 
     public static final String CORE_NATIVE_CLASSES = "core_native_classes";
     public static final String ICU_DATA_PATH = "icu.data.path";
@@ -44,7 +43,7 @@
     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";
+    public static final String LIBANDROID_RUNTIME_NAME = "android_runtime";
 
     private static String sInitialDir = new File("").getAbsolutePath();
 
@@ -68,7 +67,7 @@
     }
 
     private static void log(String message) {
-        sOut.println("ClassLoadHook: " + message);
+        System.out.println("ClassLoadHook: " + message);
     }
 
     private static void log(String fmt, Object... args) {
@@ -92,13 +91,6 @@
         }
     }
 
-    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;
 
     /**
@@ -115,7 +107,7 @@
         // 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"))) {
+        if ("1".equals(System.getenv("RAVENWOOD_DUMP_PROPERTIES"))) {
             log("Java system properties:");
             dumpSystemProperties();
         }
@@ -141,7 +133,7 @@
         setProperty(ICU_DATA_PATH, VALUE_N_A);
         setProperty(KEYBOARD_PATHS, VALUE_N_A);
 
-        loadJniLibrary(LIBANDROID_RUNTIME_NAME);
+        RavenwoodUtils.loadJniLibrary(LIBANDROID_RUNTIME_NAME);
     }
 
     /**
@@ -156,7 +148,7 @@
     };
 
     /**
-     * @return if a given method is a native method or not.
+     * @return if a given class has any native method or not.
      */
     private static boolean hasNativeMethod(Class<?> clazz) {
         for (var method : clazz.getDeclaredMethods()) {
diff --git a/ravenwood/services-test/test/com/android/ravenwood/RavenwoodServicesDependenciesTest.java b/ravenwood/services-test/test/com/android/ravenwood/RavenwoodServicesDependenciesTest.java
new file mode 100644
index 0000000..efe468d
--- /dev/null
+++ b/ravenwood/services-test/test/com/android/ravenwood/RavenwoodServicesDependenciesTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ravenwood;
+
+import static org.junit.Assert.assertEquals;
+
+import android.platform.test.ravenwood.RavenwoodRule;
+import android.ravenwood.example.BlueManager;
+import android.ravenwood.example.RedManager;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class RavenwoodServicesDependenciesTest {
+    // NOTE: we carefully only ask for RedManager here, and rely on Ravenwood internals to spin
+    // up the implicit dependency on BlueManager
+    @Rule
+    public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
+            .setProcessSystem()
+            .setServicesRequired(RedManager.class)
+            .build();
+
+    @Test
+    public void testDirect() {
+        final RedManager red = mRavenwood.getContext().getSystemService(
+                RedManager.class);
+        assertEquals("blue+red", red.getInterfaceDescriptor());
+    }
+
+    @Test
+    public void testIndirect() {
+        final BlueManager blue = mRavenwood.getContext().getSystemService(
+                BlueManager.class);
+        assertEquals("blue", blue.getInterfaceDescriptor());
+    }
+}
diff --git a/ravenwood/test-authors.md b/ravenwood/test-authors.md
index 9179a62..7c0cee8 100644
--- a/ravenwood/test-authors.md
+++ b/ravenwood/test-authors.md
@@ -112,6 +112,24 @@
 
 This naturally composes together well with any `RavenwoodRule` that your test may need.
 
+While `SetFlagsRule` is generally a best-practice (as it can explicitly confirm behaviors for both "on" and "off" states), you may need to write tests that use `CheckFlagsRule` (such as when writing CTS).  Ravenwood currently supports `CheckFlagsRule` by offering "all-on" and "all-off" behaviors:
+
+```
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.flag.junit.RavenwoodFlagsValueProvider;
+import android.platform.test.ravenwood.RavenwoodRule;
+
+@RunWith(AndroidJUnit4.class)
+public class MyCodeTest {
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isUnderRavenwood()
+            ? RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule()
+            : DeviceFlagsValueProvider.createCheckFlagsRule();
+```
+
+Ravenwood currently doesn't have knowledge of the "default" value of any flags, so using `createAllOnCheckFlagsRule()` is recommended to verify the widest possible set of behaviors.  The example code above falls back to using default values from `DeviceFlagsValueProvider` when not running on Ravenwood.
+
 ## Strategies for migration/bivalent tests
 
 Ravenwood aims to support tests that are written in a “bivalent” way, where the same test code can be dual-compiled to run on both a real Android device and under a Ravenwood environment.
diff --git a/rs/java/android/renderscript/ScriptC.java b/rs/java/android/renderscript/ScriptC.java
index 67c2caa..e9f6031 100644
--- a/rs/java/android/renderscript/ScriptC.java
+++ b/rs/java/android/renderscript/ScriptC.java
@@ -38,12 +38,12 @@
     private static final String TAG = "ScriptC";
 
     /**
-     * In targetSdkVersion 35 and above, Renderscript's ScriptC stops being supported
+     * In targetSdkVersion 36 and above, Renderscript's ScriptC stops being supported
      * and an exception is thrown when the class is instantiated.
-     * In targetSdkVersion 34 and below, Renderscript's ScriptC still works.
+     * In targetSdkVersion 35 and below, Renderscript's ScriptC still works.
      */
     @ChangeId
-    @EnabledAfter(targetSdkVersion = 35)
+    @EnabledAfter(targetSdkVersion = 36)
     private static final long RENDERSCRIPT_SCRIPTC_DEPRECATION_CHANGE_ID = 297019750L;
 
     /**
@@ -101,9 +101,21 @@
         setID(id);
     }
 
-    private static void throwExceptionIfSDKTooHigh() {
+    private static void throwExceptionIfScriptCUnsupported() {
+        // Checks that this device actually does have an ABI that supports ScriptC.
+        //
+        // For an explanation as to why `System.loadLibrary` is used, see discussion at
+        // https://android-review.googlesource.com/c/platform/frameworks/base/+/2957974/comment/2f908b80_a05292ee
+        try {
+            System.loadLibrary("RS");
+        } catch (UnsatisfiedLinkError e) {
+            String s = "This device does not have an ABI that supports ScriptC.";
+            throw new UnsupportedOperationException(s);
+        }
+
+        // Throw an exception if the target API is 36 or above
         String message =
-                "ScriptC scripts are not supported when targeting an API Level >= 35. Please refer "
+                "ScriptC scripts are not supported when targeting an API Level >= 36. Please refer "
                     + "to https://developer.android.com/guide/topics/renderscript/migration-guide "
                     + "for proposed alternatives.";
         Slog.w(TAG, message);
@@ -113,7 +125,7 @@
     }
 
     private static synchronized long internalCreate(RenderScript rs, Resources resources, int resourceID) {
-        throwExceptionIfSDKTooHigh();
+        throwExceptionIfScriptCUnsupported();
         byte[] pgm;
         int pgmLength;
         InputStream is = resources.openRawResource(resourceID);
@@ -150,7 +162,7 @@
 
     private static synchronized long internalStringCreate(RenderScript rs, String resName, byte[] bitcode) {
         //        Log.v(TAG, "Create script for resource = " + resName);
-        throwExceptionIfSDKTooHigh();
+        throwExceptionIfScriptCUnsupported();
         return rs.nScriptCCreate(resName, RenderScript.getCachePath(), bitcode, bitcode.length);
     }
 }
diff --git a/sax/tests/saxtests/Android.bp b/sax/tests/saxtests/Android.bp
index cbd19c3..446ee93 100644
--- a/sax/tests/saxtests/Android.bp
+++ b/sax/tests/saxtests/Android.bp
@@ -15,6 +15,9 @@
         "android.test.runner",
         "android.test.base",
     ],
-    static_libs: ["junit"],
+    static_libs: [
+        "junit",
+        "androidx.test.rules",
+    ],
     platform_apis: true,
 }
diff --git a/sax/tests/saxtests/src/android/sax/SafeSaxTest.java b/sax/tests/saxtests/src/android/sax/SafeSaxTest.java
index a68fc9a..2a08f54 100644
--- a/sax/tests/saxtests/src/android/sax/SafeSaxTest.java
+++ b/sax/tests/saxtests/src/android/sax/SafeSaxTest.java
@@ -17,18 +17,16 @@
 package android.sax;
 
 import android.graphics.Bitmap;
-import android.sax.Element;
-import android.sax.ElementListener;
-import android.sax.EndTextElementListener;
-import android.sax.RootElement;
-import android.sax.StartElementListener;
-import android.sax.TextElementListener;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 import android.util.Xml;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
+
+import com.android.frameworks.saxtests.R;
 import com.android.internal.util.XmlUtils;
+
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
@@ -40,8 +38,6 @@
 import java.io.InputStream;
 import java.time.Instant;
 
-import com.android.frameworks.saxtests.R;
-
 public class SafeSaxTest extends AndroidTestCase {
 
     private static final String TAG = SafeSaxTest.class.getName();
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 16119d11..54e545d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -16,6 +16,8 @@
 
 package com.android.server.accessibility;
 
+import static android.view.InputDevice.SOURCE_CLASS_POINTER;
+import static android.view.MotionEvent.ACTION_SCROLL;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
 
@@ -425,6 +427,12 @@
 
     boolean shouldProcessMultiDeviceEvent(InputEvent event, int policyFlags) {
         if (event instanceof MotionEvent motion) {
+            if (!motion.isFromSource(SOURCE_CLASS_POINTER) || motion.getAction() == ACTION_SCROLL) {
+                // Non-pointer events are focus-dispatched and don't require special logic.
+                // Scroll events are stand-alone and therefore can be considered to not be part of
+                // a stream.
+                return true;
+            }
             // Only allow 1 device to be sending motion events at a time
             // If the event is from an active device, let it through.
             // If the event is not from an active device, only let it through if it starts a new
@@ -481,7 +489,7 @@
     }
 
     private void processMotionEvent(EventStreamState state, MotionEvent event, int policyFlags) {
-        if (!state.shouldProcessScroll() && event.getActionMasked() == MotionEvent.ACTION_SCROLL) {
+        if (!state.shouldProcessScroll() && event.getActionMasked() == ACTION_SCROLL) {
             super.onInputEvent(event, policyFlags);
             return;
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 46db624..cbb66dc 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3460,13 +3460,20 @@
         if (!mMagnificationController.supportWindowMagnification()) {
             return;
         }
-        final boolean connect = (userState.isShortcutMagnificationEnabledLocked()
+
+        final boolean shortcutEnabled = (userState.isShortcutMagnificationEnabledLocked()
                 || userState.isMagnificationSingleFingerTripleTapEnabledLocked()
                 || (Flags.enableMagnificationMultipleFingerMultipleTapGesture()
-                && userState.isMagnificationTwoFingerTripleTapEnabledLocked()))
-                && (userState.getMagnificationCapabilitiesLocked()
-                != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN)
+                    && userState.isMagnificationTwoFingerTripleTapEnabledLocked()));
+
+        final boolean createConnectionForCurrentCapability =
+                com.android.window.flags.Flags.magnificationAlwaysDrawFullscreenBorder()
+                        || (userState.getMagnificationCapabilitiesLocked()
+                                != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+
+        final boolean connect = (shortcutEnabled && createConnectionForCurrentCapability)
                 || userHasMagnificationServicesLocked(userState);
+
         getMagnificationConnectionManager().requestConnection(connect);
     }
 
@@ -4652,8 +4659,8 @@
     public void onShellCommand(FileDescriptor in, FileDescriptor out,
             FileDescriptor err, String[] args, ShellCallback callback,
             ResultReceiver resultReceiver) {
-        new AccessibilityShellCommand(this, mSystemActionPerformer).exec(this, in, out, err, args,
-                callback, resultReceiver);
+        new AccessibilityShellCommand(mContext, this, mSystemActionPerformer)
+                .exec(this, in, out, err, args, callback, resultReceiver);
     }
 
     private final class InteractionBridge {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityShellCommand.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityShellCommand.java
index 8cf5547..4908032 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityShellCommand.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityShellCommand.java
@@ -16,8 +16,10 @@
 
 package com.android.server.accessibility;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.app.ActivityManager;
+import android.content.Context;
 import android.os.Binder;
 import android.os.Process;
 import android.os.ShellCommand;
@@ -26,18 +28,27 @@
 import com.android.server.LocalServices;
 import com.android.server.wm.WindowManagerInternal;
 
+import java.io.File;
+import java.io.IOException;
 import java.io.PrintWriter;
 
 /**
  * Shell command implementation for the accessibility manager service
  */
 final class AccessibilityShellCommand extends ShellCommand {
-    final @NonNull AccessibilityManagerService mService;
-    final @NonNull SystemActionPerformer mSystemActionPerformer;
-    final @NonNull WindowManagerInternal mWindowManagerService;
+    @NonNull
+    final Context mContext;
+    @NonNull
+    final AccessibilityManagerService mService;
+    @NonNull
+    final SystemActionPerformer mSystemActionPerformer;
+    @NonNull
+    final WindowManagerInternal mWindowManagerService;
 
-    AccessibilityShellCommand(@NonNull AccessibilityManagerService service,
+    AccessibilityShellCommand(@NonNull Context context,
+            @NonNull AccessibilityManagerService service,
             @NonNull SystemActionPerformer systemActionPerformer) {
+        mContext = context;
         mService = service;
         mSystemActionPerformer = systemActionPerformer;
         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
@@ -61,6 +72,8 @@
             case "start-trace":
             case "stop-trace":
                 return mService.getTraceManager().onShellCommand(cmd, this);
+            case "check-hidraw":
+                return checkHidraw();
         }
         return -1;
     }
@@ -106,6 +119,67 @@
         return -1;
     }
 
+    private int checkHidraw() {
+        mContext.enforceCallingPermission(Manifest.permission.MANAGE_ACCESSIBILITY,
+                "Missing MANAGE_ACCESSIBILITY permission");
+        String subcommand = getNextArgRequired();
+        File hidrawNode = new File(getNextArgRequired());
+        switch (subcommand) {
+            case "read" -> {
+                return checkHidrawRead(hidrawNode);
+            }
+            case "write" -> {
+                return checkHidrawWrite(hidrawNode);
+            }
+            case "descriptor" -> {
+                return checkHidrawDescriptor(hidrawNode);
+            }
+            default -> {
+                getErrPrintWriter().print("Unknown subcommand " + subcommand);
+                return -1;
+            }
+        }
+    }
+
+    private int checkHidrawRead(File hidrawNode) {
+        if (!hidrawNode.canRead()) {
+            getErrPrintWriter().println("Unable to read from " + hidrawNode);
+            return -1;
+        }
+        // Tests executing this command using UiAutomation#executeShellCommand will not receive
+        // the command's exit value, so print the path to stdout to indicate success.
+        getOutPrintWriter().print(hidrawNode.getAbsolutePath());
+        return 0;
+    }
+
+    private int checkHidrawWrite(File hidrawNode) {
+        if (!hidrawNode.canWrite()) {
+            getErrPrintWriter().println("Unable to write to " + hidrawNode);
+            return -1;
+        }
+        // Tests executing this command using UiAutomation#executeShellCommand will not receive
+        // the command's exit value, so print the path to stdout to indicate success.
+        getOutPrintWriter().print(hidrawNode.getAbsolutePath());
+        return 0;
+    }
+
+    private int checkHidrawDescriptor(File hidrawNode) {
+        BrailleDisplayConnection.BrailleDisplayScanner scanner =
+                BrailleDisplayConnection.createScannerForShell();
+        byte[] descriptor = scanner.getDeviceReportDescriptor(hidrawNode.toPath());
+        if (descriptor == null) {
+            getErrPrintWriter().println("Unable to read descriptor for " + hidrawNode);
+            return -1;
+        }
+        try {
+            // Print the descriptor bytes to stdout.
+            getRawOutputStream().write(descriptor);
+            return 0;
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     private Integer parseUserId() {
         final String option = getNextOption();
         if (option != null) {
@@ -131,6 +205,8 @@
         pw.println("    Get whether binding to services provided by instant apps is allowed.");
         pw.println("  call-system-action <ACTION_ID>");
         pw.println("    Calls the system action with the given action id.");
+        pw.println("  check-hidraw [read|write|descriptor] <HIDRAW_NODE_PATH>");
+        pw.println("    Checks if the system can perform various actions on the HIDRAW node.");
         mService.getTraceManager().onHelp(pw);
     }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/BrailleDisplayConnection.java b/services/accessibility/java/com/android/server/accessibility/BrailleDisplayConnection.java
index 40b6ff0..8b41873 100644
--- a/services/accessibility/java/com/android/server/accessibility/BrailleDisplayConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/BrailleDisplayConnection.java
@@ -116,6 +116,13 @@
     }
 
     /**
+     * Used for `cmd accessibility` to check hidraw access.
+     */
+    static BrailleDisplayScanner createScannerForShell() {
+        return getDefaultNativeScanner(new DefaultNativeInterface());
+    }
+
+    /**
      * Interface to scan for properties of connected Braille displays.
      *
      * <p>Helps simplify testing Braille Display APIs using test data without requiring
@@ -125,7 +132,6 @@
      * @see #getDefaultNativeScanner
      * @see #setTestData
      */
-    @VisibleForTesting
     interface BrailleDisplayScanner {
         Collection<Path> getHidrawNodePaths(@NonNull Path directory);
 
@@ -441,7 +447,7 @@
      * from HIDRAW nodes and perform ioctls using the provided {@link NativeInterface}.
      */
     @VisibleForTesting
-    BrailleDisplayScanner getDefaultNativeScanner(@NonNull NativeInterface nativeInterface) {
+    static BrailleDisplayScanner getDefaultNativeScanner(@NonNull NativeInterface nativeInterface) {
         Objects.requireNonNull(nativeInterface);
         return new BrailleDisplayScanner() {
             private static final String HIDRAW_DEVICE_GLOB = "hidraw*";
@@ -576,7 +582,7 @@
     }
 
     /** Native interface that actually calls native HIDRAW ioctls. */
-    private class DefaultNativeInterface implements NativeInterface {
+    private static class DefaultNativeInterface implements NativeInterface {
         @Override
         public int getHidrawDescSize(int fd) {
             return nativeGetHidrawDescSize(fd);
@@ -598,11 +604,11 @@
         }
     }
 
-    private native int nativeGetHidrawDescSize(int fd);
+    private static native int nativeGetHidrawDescSize(int fd);
 
-    private native byte[] nativeGetHidrawDesc(int fd, int descSize);
+    private static native byte[] nativeGetHidrawDesc(int fd, int descSize);
 
-    private native String nativeGetHidrawUniq(int fd);
+    private static native String nativeGetHidrawUniq(int fd);
 
-    private native int nativeGetHidrawBusType(int fd);
+    private static native int nativeGetHidrawBusType(int fd);
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index f4ea754..279bd72 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -1004,17 +1004,19 @@
                                     && overscrollState(event, mFirstPointerDownLocation)
                                     == OVERSCROLL_VERTICAL_EDGE) {
                                 transitionToDelegatingStateAndClear();
-                            } // TODO(b/319537921): should there be an else here?
-                            //Primary pointer is swiping, so transit to PanningScalingState
-                            transitToPanningScalingStateAndClear();
+                            } else {
+                                //Primary pointer is swiping, so transit to PanningScalingState
+                                transitToPanningScalingStateAndClear();
+                            }
                         } else if (mIsSinglePanningEnabled
                                 && isActivated()
                                 && event.getPointerCount() == 1) {
                             if (overscrollState(event, mFirstPointerDownLocation)
                                     == OVERSCROLL_VERTICAL_EDGE) {
                                 transitionToDelegatingStateAndClear();
-                            } // TODO(b/319537921): should there be an else here?
-                            transitToSinglePanningStateAndClear();
+                            } else {
+                                transitToSinglePanningStateAndClear();
+                            }
                         } else if (!mIsTwoFingerCountReached) {
                             // If it is a two-finger gesture, do not transition to the
                             // delegating state to ensure the reachability of
@@ -1257,17 +1259,19 @@
                                     && overscrollState(event, mFirstPointerDownLocation)
                                     == OVERSCROLL_VERTICAL_EDGE) {
                                 transitionToDelegatingStateAndClear();
+                            } else {
+                                //Primary pointer is swiping, so transit to PanningScalingState
+                                transitToPanningScalingStateAndClear();
                             }
-                            //Primary pointer is swiping, so transit to PanningScalingState
-                            transitToPanningScalingStateAndClear();
                         } else if (mIsSinglePanningEnabled
                                 && isActivated()
                                 && event.getPointerCount() == 1) {
                             if (overscrollState(event, mFirstPointerDownLocation)
                                     == OVERSCROLL_VERTICAL_EDGE) {
                                 transitionToDelegatingStateAndClear();
+                            } else {
+                                transitToSinglePanningStateAndClear();
                             }
-                            transitToSinglePanningStateAndClear();
                         } else {
                             transitionToDelegatingStateAndClear();
                         }
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
index e11c36a..bc14342 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
@@ -674,6 +674,23 @@
     }
 
     /**
+     * Notify Fullscreen magnification activation changes.
+     */
+    public boolean onFullscreenMagnificationActivationChanged(int displayId, boolean activated) {
+        synchronized (mLock) {
+            waitForConnectionIfNeeded();
+            if (mConnectionWrapper == null) {
+                Slog.w(TAG,
+                        "onFullscreenMagnificationActivationChanged mConnectionWrapper is null. "
+                                + "mConnectionState=" + connectionStateToString(mConnectionState));
+                return false;
+            }
+            return mConnectionWrapper
+                    .onFullscreenMagnificationActivationChanged(displayId, activated);
+        }
+    }
+
+    /**
      * Calculates the number of fingers in the window.
      *
      * @param displayId The logical display id.
@@ -1267,15 +1284,7 @@
             float centerY, float magnificationFrameOffsetRatioX,
             float magnificationFrameOffsetRatioY,
             MagnificationAnimationCallback animationCallback) {
-        // Wait for the connection with a timeout.
-        final long endMillis = SystemClock.uptimeMillis() + WAIT_CONNECTION_TIMEOUT_MILLIS;
-        while (mConnectionState == CONNECTING && (SystemClock.uptimeMillis() < endMillis)) {
-            try {
-                mLock.wait(endMillis - SystemClock.uptimeMillis());
-            } catch (InterruptedException ie) {
-                /* ignore */
-            }
-        }
+        waitForConnectionIfNeeded();
         if (mConnectionWrapper == null) {
             Slog.w(TAG,
                     "enableWindowMagnificationInternal mConnectionWrapper is null. "
@@ -1317,4 +1326,16 @@
         return mConnectionWrapper != null && mConnectionWrapper.moveWindowMagnifierToPosition(
                 displayId, positionX, positionY, animationCallback);
     }
+
+    private void waitForConnectionIfNeeded() {
+        // Wait for the connection with a timeout.
+        final long endMillis = SystemClock.uptimeMillis() + WAIT_CONNECTION_TIMEOUT_MILLIS;
+        while (mConnectionState == CONNECTING && (SystemClock.uptimeMillis() < endMillis)) {
+            try {
+                mLock.wait(endMillis - SystemClock.uptimeMillis());
+            } catch (InterruptedException ie) {
+                /* ignore */
+            }
+        }
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
index db5b313..f6fb24f 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
@@ -58,6 +58,22 @@
         mConnection.asBinder().linkToDeath(deathRecipient, 0);
     }
 
+    boolean onFullscreenMagnificationActivationChanged(int displayId, boolean activated) {
+        if (mTrace.isA11yTracingEnabledForTypes(FLAGS_MAGNIFICATION_CONNECTION)) {
+            mTrace.logTrace(TAG + ".onFullscreenMagnificationActivationChanged",
+                    FLAGS_MAGNIFICATION_CONNECTION);
+        }
+        try {
+            mConnection.onFullscreenMagnificationActivationChanged(displayId, activated);
+        } catch (RemoteException e) {
+            if (DBG) {
+                Slog.e(TAG, "Error calling onFullscreenMagnificationActivationChanged");
+            }
+            return false;
+        }
+        return true;
+    }
+
     boolean enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
             float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY,
             @Nullable MagnificationAnimationCallback callback) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 52e123a..0d5fd14 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -50,6 +50,7 @@
 import com.android.server.LocalServices;
 import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.wm.WindowManagerInternal;
+import com.android.window.flags.Flags;
 
 import java.util.concurrent.Executor;
 
@@ -586,6 +587,11 @@
 
     @Override
     public void onFullScreenMagnificationActivationState(int displayId, boolean activated) {
+        if (Flags.magnificationAlwaysDrawFullscreenBorder()) {
+            getMagnificationConnectionManager()
+                    .onFullscreenMagnificationActivationChanged(displayId, activated);
+        }
+
         if (activated) {
             synchronized (mLock) {
                 mFullScreenModeEnabledTimeArray.put(displayId, SystemClock.uptimeMillis());
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 6f45f60..29b9d44 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -476,8 +476,12 @@
             } else {
                 // If the package is being updated, we'll receive a PACKAGE_ADDED
                 // shortly, otherwise it is removed permanently.
-                final boolean packageRemovedPermanently = (extras == null
-                        || !extras.getBoolean(Intent.EXTRA_REPLACING, false));
+                boolean isReplacing = extras != null && extras.getBoolean(Intent.EXTRA_REPLACING,
+                        false);
+                boolean isArchival = extras != null && extras.getBoolean(Intent.EXTRA_ARCHIVAL,
+                        false);
+                final boolean packageRemovedPermanently =
+                        (extras == null || !isReplacing || (isReplacing && isArchival));
 
                 if (packageRemovedPermanently) {
                     for (String pkgName : pkgList) {
@@ -2074,6 +2078,7 @@
     private void handleNotifyAppWidgetViewDataChanged(Host host, IAppWidgetHost callbacks,
             int appWidgetId, int viewId, long requestId) {
         try {
+            Slog.d(TAG, "Trying to notify widget view data changed");
             callbacks.viewDataChanged(appWidgetId, viewId);
             host.lastWidgetUpdateSequenceNo = requestId;
         } catch (RemoteException re) {
@@ -2158,6 +2163,9 @@
     private void handleNotifyUpdateAppWidget(Host host, IAppWidgetHost callbacks,
             int appWidgetId, RemoteViews views, long requestId) {
         try {
+            Slog.d(TAG, "Trying to notify widget update for package "
+                    + (views == null ? "null" : views.getPackage())
+                    + " with widget id: " + appWidgetId);
             callbacks.updateAppWidget(appWidgetId, views);
             host.lastWidgetUpdateSequenceNo = requestId;
         } catch (RemoteException re) {
@@ -2196,6 +2204,7 @@
     private void handleNotifyProviderChanged(Host host, IAppWidgetHost callbacks,
             int appWidgetId, AppWidgetProviderInfo info, long requestId) {
         try {
+            Slog.d(TAG, "Trying to notify provider update");
             callbacks.providerChanged(appWidgetId, info);
             host.lastWidgetUpdateSequenceNo = requestId;
         } catch (RemoteException re) {
@@ -2239,6 +2248,7 @@
     private void handleNotifyAppWidgetRemoved(Host host, IAppWidgetHost callbacks, int appWidgetId,
             long requestId) {
         try {
+            Slog.d(TAG, "Trying to notify widget removed");
             callbacks.appWidgetRemoved(appWidgetId);
             host.lastWidgetUpdateSequenceNo = requestId;
         } catch (RemoteException re) {
@@ -2286,6 +2296,7 @@
 
     private void handleNotifyProvidersChanged(Host host, IAppWidgetHost callbacks) {
         try {
+            Slog.d(TAG, "Trying to notify widget providers changed");
             callbacks.providersChanged();
         } catch (RemoteException re) {
             synchronized (mLock) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index e1291e5..285e54c 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -33,8 +33,10 @@
 import android.annotation.Nullable;
 import android.app.ActivityManagerInternal;
 import android.content.ComponentName;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.graphics.Rect;
 import android.metrics.LogMaker;
@@ -251,6 +253,26 @@
     @Override // from PerUserSystemService
     protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
             throws NameNotFoundException {
+        final List<ResolveInfo> resolveInfos =
+                getContext().getPackageManager().queryIntentServicesAsUser(
+                        new Intent(AutofillService.SERVICE_INTERFACE),
+                        PackageManager.GET_META_DATA,
+                        mUserId);
+        boolean currentPackageStillHasAutofillIntentFilter = false;
+        for (ResolveInfo resolveInfo : resolveInfos) {
+            final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+            if (serviceInfo.getComponentName().equals(serviceComponent)) {
+                currentPackageStillHasAutofillIntentFilter = true;
+                break;
+            }
+        }
+        if (!currentPackageStillHasAutofillIntentFilter) {
+            Slog.w(TAG,
+                    "Autofill service from '" + serviceComponent.getPackageName() + "' does"
+                            + "not have intent filter " + AutofillService.SERVICE_INTERFACE);
+            throw new SecurityException("Service does not declare intent filter "
+                            + AutofillService.SERVICE_INTERFACE);
+        }
         mInfo = new AutofillServiceInfo(getContext(), serviceComponent, mUserId);
         return mInfo.getServiceInfo();
     }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index c4341b9..551297b 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2802,9 +2802,10 @@
 
         final int datasetIdx = AutofillManager.getDatasetIdFromAuthenticationId(
                 authenticationId);
+        Dataset dataset = null;
         // Authenticated a dataset - reset view state regardless if we got a response or a dataset
         if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) {
-            final Dataset dataset = authenticatedResponse.getDatasets().get(datasetIdx);
+            dataset = authenticatedResponse.getDatasets().get(datasetIdx);
             if (dataset == null) {
                 Slog.w(TAG, "no dataset with index " + datasetIdx + " on fill response");
                 mPresentationStatsEventLogger.maybeSetAuthenticationResult(
@@ -2819,12 +2820,29 @@
         mSessionFlags.mExpiredResponse = false;
 
         final Parcelable result = data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT);
+        final GetCredentialException exception = data.getSerializable(
+                CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION,
+                GetCredentialException.class);
 
         final Bundle newClientState = data.getBundle(AutofillManager.EXTRA_CLIENT_STATE);
         if (sDebug) {
             Slog.d(TAG, "setAuthenticationResultLocked(): result=" + result
                     + ", clientState=" + newClientState + ", authenticationId=" + authenticationId);
         }
+        if (Flags.autofillCredmanDevIntegration() && exception != null
+                && exception instanceof GetCredentialException) {
+            if (dataset != null && dataset.getFieldIds().size() == 1) {
+                if (sDebug) {
+                    Slog.d(TAG, "setAuthenticationResultLocked(): result returns with"
+                            + "Credential Manager Exception");
+                }
+                AutofillId autofillId = dataset.getFieldIds().get(0);
+                sendCredentialManagerResponseToApp(/*response=*/ null,
+                        (GetCredentialException) exception, autofillId);
+            }
+            return;
+        }
+
         if (result instanceof FillResponse) {
             if (sDebug) {
                 Slog.d(TAG, "setAuthenticationResultLocked(): received FillResponse from"
@@ -2840,13 +2858,21 @@
             }
             if (Flags.autofillCredmanDevIntegration()) {
                 GetCredentialResponse response = (GetCredentialResponse) result;
-                sendCredentialManagerResponseToApp(response,
-                        /*exception=*/ null, response.getAutofillId());
+                if (dataset != null && dataset.getFieldIds().size() == 1) {
+                    AutofillId autofillId = dataset.getFieldIds().get(0);
+                    if (sDebug) {
+                        Slog.d(TAG, "Received GetCredentialResponse from authentication flow,"
+                                + "for autofillId: " + autofillId);
+                    }
+                    sendCredentialManagerResponseToApp(response,
+                            /*exception=*/ null, autofillId);
+                }
             } else if (Flags.autofillCredmanIntegration()) {
-                Dataset dataset = getDatasetFromCredentialResponse(
+                Dataset datasetFromCredentialResponse = getDatasetFromCredentialResponse(
                         (GetCredentialResponse) result);
-                if (dataset != null) {
-                    autoFill(requestId, datasetIdx, dataset, false, UI_TYPE_UNKNOWN);
+                if (datasetFromCredentialResponse != null) {
+                    autoFill(requestId, datasetIdx, datasetFromCredentialResponse,
+                            false, UI_TYPE_UNKNOWN);
                 }
             }
         } else if (result instanceof Dataset) {
@@ -2863,12 +2889,12 @@
                     if (sDebug) Slog.d(TAG,  "Updating client state from auth dataset");
                     mClientState = newClientState;
                 }
-                Dataset dataset = getEffectiveDatasetForAuthentication((Dataset) result);
+                Dataset datasetFromResult = getEffectiveDatasetForAuthentication((Dataset) result);
                 final Dataset oldDataset = authenticatedResponse.getDatasets().get(datasetIdx);
                 if (!isAuthResultDatasetEphemeral(oldDataset, data)) {
-                    authenticatedResponse.getDatasets().set(datasetIdx, dataset);
+                    authenticatedResponse.getDatasets().set(datasetIdx, datasetFromResult);
                 }
-                autoFill(requestId, datasetIdx, dataset, false, UI_TYPE_UNKNOWN);
+                autoFill(requestId, datasetIdx, datasetFromResult, false, UI_TYPE_UNKNOWN);
             } else {
                 Slog.w(TAG, "invalid index (" + datasetIdx + ") for authentication id "
                         + authenticationId);
@@ -4756,7 +4782,6 @@
         }
 
         if (isCredmanIntegrationActive(response)) {
-            Slog.d(TAG, "Attempting to add Credential Manager callback to pinned entries");
             addCredentialManagerCallback(response);
         }
 
@@ -5052,12 +5077,16 @@
     }
 
     private void addCredentialManagerCallbackForDataset(Dataset dataset, int requestId) {
+        AutofillId autofillId = null;
+        if (dataset != null && dataset.getFieldIds().size() == 1) {
+            autofillId = dataset.getFieldIds().get(0);
+        }
+        final AutofillId finalAutofillId = autofillId;
         final ResultReceiver resultReceiver = new ResultReceiver(mHandler) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
                 if (resultCode == SUCCESS_CREDMAN_SELECTOR) {
                     Slog.d(TAG, "onReceiveResult from Credential Manager bottom sheet");
-                    boolean isCredmanCallbackInvoked = false;
                     GetCredentialResponse getCredentialResponse =
                             resultData.getParcelable(
                                     CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE,
@@ -5065,7 +5094,7 @@
 
                     if (Flags.autofillCredmanDevIntegration()) {
                         sendCredentialManagerResponseToApp(getCredentialResponse,
-                                /*exception=*/ null, getCredentialResponse.getAutofillId());
+                                /*exception=*/ null, finalAutofillId);
                     } else {
                         Dataset datasetFromCredential = getDatasetFromCredentialResponse(
                                 getCredentialResponse);
@@ -5082,7 +5111,9 @@
                         Slog.w(TAG, "Credman bottom sheet from pinned "
                                 + "entry failed with: + " + exception[0] + " , "
                                 + exception[1]);
-                        // TODO(b/326313420): Propagate exception
+                        sendCredentialManagerResponseToApp(/*response=*/ null,
+                                new GetCredentialException(exception[0], exception[1]),
+                                finalAutofillId);
                     }
                 } else {
                     Slog.d(TAG, "Unknown resultCode from credential "
@@ -5094,6 +5125,10 @@
                 toIpcFriendlyResultReceiver(resultReceiver);
 
         Intent metadataIntent = dataset.getCredentialFillInIntent();
+        if (metadataIntent == null) {
+            metadataIntent = new Intent();
+        }
+
         metadataIntent.putExtra(
                 android.credentials.selection.Constants.EXTRA_FINAL_RESPONSE_RECEIVER,
                 ipcFriendlyResultReceiver);
@@ -5677,7 +5712,6 @@
                 /* isPrimary= */ true);
         updateFillDialogTriggerIdsLocked();
         updateTrackedIdsLocked();
-
         if (mCurrentViewId == null) {
             return;
         }
@@ -6380,7 +6414,8 @@
                     }
                 }
                 if (exception != null) {
-                    // TODO(b/326313420): Add Exception support
+                    mClient.onGetCredentialException(id, viewId, exception.getType(),
+                            exception.getMessage());
                 } else if (response != null) {
                     mClient.onGetCredentialResponse(id, viewId, response);
                 } else {
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index e666442..8fece82 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -167,6 +167,9 @@
     // List of packages that have RestoreAnyVersion set to true but do not support  V-> U downgrade.
     private List<String> mVToUDenylist;
 
+    // Whether we have already initialised the V to U allowlist/denylist
+    private Boolean mAreVToUListsSet = false;
+
     // Key/value: bookkeeping about staged data and files for agent access
     private File mBackupDataName;
     private File mStageName;
@@ -235,18 +238,6 @@
                         backupManagerService.getAgentTimeoutParameters(),
                         "Timeout parameters cannot be null");
         mBackupEligibilityRules = backupEligibilityRules;
-        mVToUAllowlist =
-            createVToUList(
-                Settings.Secure.getStringForUser(
-                    backupManagerService.getContext().getContentResolver(),
-                    Settings.Secure.V_TO_U_RESTORE_ALLOWLIST,
-                    mUserId));
-        mVToUDenylist =
-            createVToUList(
-                Settings.Secure.getStringForUser(
-                    backupManagerService.getContext().getContentResolver(),
-                    Settings.Secure.V_TO_U_RESTORE_DENYLIST,
-                    mUserId));
 
         if (targetPackage != null) {
             // Single package restore
@@ -661,11 +652,38 @@
                 // installed.  If the app has not declared that it is prepared to
                 // handle this case, we do not attempt the restore.
                 if (mIsSystemRestore
-                    && isVToUDowngrade(mPmAgent.getSourceSdk(), android.os.Build.VERSION.SDK_INT)) {
+                        && isVToUDowngrade(mPmAgent.getSourceSdk(),
+                        android.os.Build.VERSION.SDK_INT)) {
+                    if (!mAreVToUListsSet) {
+                        mVToUAllowlist =
+                                createVToUList(
+                                        Settings.Secure.getStringForUser(
+                                            backupManagerService.getContext().getContentResolver(),
+                                            Settings.Secure.V_TO_U_RESTORE_ALLOWLIST,
+                                            mUserId));
+                        mVToUDenylist =
+                                createVToUList(
+                                        Settings.Secure.getStringForUser(
+                                            backupManagerService.getContext().getContentResolver(),
+                                            Settings.Secure.V_TO_U_RESTORE_DENYLIST,
+                                            mUserId));
+                        logVToUListsToBMM();
+                        mAreVToUListsSet = true;
+                    }
                     if (isPackageEligibleForVToURestore(mCurrentPackage)) {
+                        mBackupManagerMonitorEventSender.monitorEvent(
+                                BackupManagerMonitor.LOG_EVENT_ID_V_TO_U_RESTORE_PKG_ELIGIBLE,
+                                mCurrentPackage,
+                                BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+                                addRestoreOperationTypeToEvent(/* extras= */null));
                         Slog.i(TAG, "Package " + pkgName
                                 + " is eligible for V to U downgrade scenario");
                     } else {
+                        mBackupManagerMonitorEventSender.monitorEvent(
+                                BackupManagerMonitor.LOG_EVENT_ID_V_TO_U_RESTORE_PKG_NOT_ELIGIBLE,
+                                mCurrentPackage,
+                                BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+                                addRestoreOperationTypeToEvent(/* extras= */null));
                         String message = "Package not eligible for V to U downgrade scenario";
                         Slog.i(TAG, pkgName + " : " + message);
                         EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, pkgName, message);
@@ -1696,14 +1714,25 @@
         //      (and not in the denylist)
         //    - The package has restoreAnyVersion set to true and is not part of the denylist
         if (mVToUDenylist.contains(mCurrentPackage.packageName)){
+            if (DEBUG) {
+                Slog.i(TAG, mCurrentPackage.packageName + " : Package is in V to U denylist");
+            }
             return false;
         } else if ((mCurrentPackage.applicationInfo.flags
                 & ApplicationInfo.FLAG_RESTORE_ANY_VERSION)
                 == 0) {
             // package has restoreAnyVersion set to false
+            if (DEBUG) {
+                Slog.i(TAG, mCurrentPackage.packageName
+                        + " : Package has restoreAnyVersion=false and is in V to U allowlist");
+            }
             return mVToUAllowlist.contains(mCurrentPackage.packageName);
         } else {
             // package has restoreAnyVersion set to true and is nor in denylist
+            if (DEBUG) {
+                Slog.i(TAG, mCurrentPackage.packageName
+                        + " : Package has restoreAnyVersion=true and is not in V to U denylist");
+            }
             return true;
         }
     }
@@ -1748,4 +1777,31 @@
                 monitoringExtras);
     }
 
+    private void logVToUListsToBMM() {
+        // send a BMM event with the allowlist
+        Bundle monitoringExtrasAllowlist =
+                mBackupManagerMonitorEventSender.putMonitoringExtra(
+                        null,
+                        BackupManagerMonitor.EXTRA_LOG_V_TO_U_ALLOWLIST,
+                        mVToUAllowlist.toString());
+        monitoringExtrasAllowlist = addRestoreOperationTypeToEvent(monitoringExtrasAllowlist);
+        mBackupManagerMonitorEventSender.monitorEvent(
+                BackupManagerMonitor.LOG_EVENT_ID_V_TO_U_RESTORE_SET_LIST,
+                null,
+                BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+                monitoringExtrasAllowlist);
+        // send a BMM event with the denylist
+        Bundle monitoringExtrasDenylist =
+                mBackupManagerMonitorEventSender.putMonitoringExtra(
+                        null,
+                        BackupManagerMonitor.EXTRA_LOG_V_TO_U_DENYLIST,
+                        mVToUDenylist.toString());
+        monitoringExtrasDenylist = addRestoreOperationTypeToEvent(monitoringExtrasDenylist);
+        mBackupManagerMonitorEventSender.monitorEvent(
+                BackupManagerMonitor.LOG_EVENT_ID_V_TO_U_RESTORE_SET_LIST,
+                null,
+                BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+                monitoringExtrasDenylist);
+    }
+
 }
diff --git a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtils.java b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtils.java
index 797aed9..6d315ba 100644
--- a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtils.java
@@ -146,7 +146,6 @@
                         + eventBundle.getString(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME));
             }
 
-            // TODO(b/296818666): add extras to the events
             addAgentLogsIfAvailable(eventBundle, pw);
             addExtrasIfAvailable(eventBundle, pw);
         } catch (java.io.IOException e) {
@@ -203,6 +202,11 @@
      * EXTRA_LOG_RESTORE_VERSION [int]: the version of the package on the source
      * EXTRA_LOG_RESTORE_ANYWAY [bool]: if the package allows restore any version
      * EXTRA_LOG_RESTORE_VERSION_TARGET [int]: an extra to record the package version on the target
+     *
+     * When we are performing a V to U downgrade (event with id V_TO_U_RESTORE_SET_LIST) we record
+     * the value of the V to U allowlist and denylist:
+     * EXTRA_LOG_V_TO_U_ALLOWLIST[string]
+     * EXTRA_LOG_V_TO_U_DENYLIST[string]
      */
     private void addExtrasIfAvailable(Bundle eventBundle, PrintWriter pw) {
         if (eventBundle.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID) ==
@@ -216,12 +220,29 @@
                         + eventBundle.getLong(BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION));
             }
             if (eventBundle.containsKey(
-                      BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION)) {
+                    BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION)) {
                 pw.println("\t\tPackage version on target: "
                         + eventBundle.getLong(
                         BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION));
             }
         }
+
+        if (eventBundle.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID)
+                == BackupManagerMonitor.LOG_EVENT_ID_V_TO_U_RESTORE_SET_LIST) {
+            if (eventBundle.containsKey(
+                    BackupManagerMonitor.EXTRA_LOG_V_TO_U_DENYLIST)) {
+                pw.println("\t\tV to U Denylist : "
+                        + eventBundle.getString(
+                        BackupManagerMonitor.EXTRA_LOG_V_TO_U_DENYLIST));
+            }
+
+            if (eventBundle.containsKey(
+                    BackupManagerMonitor.EXTRA_LOG_V_TO_U_ALLOWLIST)) {
+                pw.println("\t\tV to U Allowllist : "
+                        + eventBundle.getString(
+                        BackupManagerMonitor.EXTRA_LOG_V_TO_U_ALLOWLIST));
+            }
+        }
     }
 
     /*
@@ -342,10 +363,14 @@
             case BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_ERROR_FULL_RESTORE ->
                     "Transport error full restore";
             case BackupManagerMonitor.LOG_EVENT_ID_RESTORE_COMPLETE -> "Restore complete";
-            case BackupManagerMonitor.LOG_EVENT_ID_START_PACKAGE_RESTORE ->
-                    "Start package restore";
-            case BackupManagerMonitor.LOG_EVENT_ID_AGENT_FAILURE ->
-                    "Agent failure";
+            case BackupManagerMonitor.LOG_EVENT_ID_START_PACKAGE_RESTORE -> "Start package restore";
+            case BackupManagerMonitor.LOG_EVENT_ID_AGENT_FAILURE -> "Agent failure";
+            case BackupManagerMonitor.LOG_EVENT_ID_V_TO_U_RESTORE_PKG_ELIGIBLE ->
+                    "V to U restore pkg eligible";
+            case BackupManagerMonitor.LOG_EVENT_ID_V_TO_U_RESTORE_PKG_NOT_ELIGIBLE ->
+                    "V to U restore pkg not eligible";
+            case BackupManagerMonitor.LOG_EVENT_ID_V_TO_U_RESTORE_SET_LIST ->
+                    "V to U restore lists";
             default -> "Unknown log event ID: " + code;
         };
         return id;
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index d0eb59d..1dab40e 100644
--- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -25,12 +25,12 @@
 import static android.content.pm.PackageManager.FEATURE_WATCH;
 
 import static com.android.server.companion.CompanionDeviceManagerService.DEBUG;
-import static com.android.server.companion.MetricUtils.logCreateAssociation;
-import static com.android.server.companion.PackageUtils.enforceUsesCompanionDeviceFeature;
-import static com.android.server.companion.PermissionsUtils.enforcePermissionsForAssociation;
-import static com.android.server.companion.RolesUtils.addRoleHolderForAssociation;
-import static com.android.server.companion.RolesUtils.isRoleHolder;
-import static com.android.server.companion.Utils.prepareForIpc;
+import static com.android.server.companion.utils.MetricUtils.logCreateAssociation;
+import static com.android.server.companion.utils.PackageUtils.enforceUsesCompanionDeviceFeature;
+import static com.android.server.companion.utils.PermissionsUtils.enforcePermissionForCreatingAssociation;
+import static com.android.server.companion.utils.RolesUtils.addRoleHolderForAssociation;
+import static com.android.server.companion.utils.RolesUtils.isRoleHolder;
+import static com.android.server.companion.utils.Utils.prepareForIpc;
 
 import static java.util.Objects.requireNonNull;
 
@@ -59,6 +59,7 @@
 import android.util.Slog;
 
 import com.android.internal.R;
+import com.android.server.companion.utils.PackageUtils;
 
 import java.util.List;
 
@@ -167,7 +168,7 @@
         }
 
         // 1. Enforce permissions and other requirements.
-        enforcePermissionsForAssociation(mContext, request, packageUid);
+        enforcePermissionForCreatingAssociation(mContext, request, packageUid);
         enforceUsesCompanionDeviceFeature(mContext, userId, packageName);
 
         // 2a. Check if association can be created without launching UI (i.e. CDM needs NEITHER
@@ -257,7 +258,7 @@
         // 1. Need to check permissions again in case something changed, since we first received
         // this request.
         try {
-            enforcePermissionsForAssociation(mContext, request, packageUid);
+            enforcePermissionForCreatingAssociation(mContext, request, packageUid);
         } catch (SecurityException e) {
             // Since, at this point the caller is our own UI, we need to catch the exception on
             // forward it back to the application via the callback.
@@ -316,6 +317,9 @@
         // If it is null, then the operation will succeed without granting any role.
         addRoleHolderForAssociation(mService.getContext(), association, success -> {
             if (success) {
+                Slog.i(TAG, "Added " + association.getDeviceProfile() + " role to userId="
+                        + association.getUserId() + ", packageName="
+                        + association.getPackageName());
                 addAssociationToStore(association);
                 sendCallbackAndFinish(association, callback, resultReceiver);
             } else {
diff --git a/services/companion/java/com/android/server/companion/AssociationRevokeProcessor.java b/services/companion/java/com/android/server/companion/AssociationRevokeProcessor.java
new file mode 100644
index 0000000..10963ea
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/AssociationRevokeProcessor.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.companion;
+
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
+
+import static com.android.internal.util.CollectionUtils.any;
+import static com.android.server.companion.utils.MetricUtils.logRemoveAssociation;
+import static com.android.server.companion.utils.RolesUtils.removeRoleHolderForAssociation;
+import static com.android.server.companion.CompanionDeviceManagerService.PerUserAssociationSet;
+
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.companion.AssociationInfo;
+import android.content.Context;
+import android.content.pm.PackageManagerInternal;
+import android.os.Binder;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.companion.datatransfer.SystemDataTransferRequestStore;
+import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A class response for Association removal.
+ */
+@SuppressLint("LongLogTag")
+public class AssociationRevokeProcessor {
+
+    private static final String TAG = "CDM_AssociationRevokeProcessor";
+    private static final boolean DEBUG = false;
+    private final @NonNull Context mContext;
+    private final @NonNull CompanionDeviceManagerService mService;
+    private final @NonNull AssociationStoreImpl mAssociationStore;
+    private final @NonNull PackageManagerInternal mPackageManagerInternal;
+    private final @NonNull CompanionDevicePresenceMonitor mDevicePresenceMonitor;
+    private final @NonNull SystemDataTransferRequestStore mSystemDataTransferRequestStore;
+    private final @NonNull CompanionApplicationController mCompanionAppController;
+    private final OnPackageVisibilityChangeListener mOnPackageVisibilityChangeListener;
+    private final ActivityManager mActivityManager;
+
+    /**
+     * A structure that consists of a set of revoked associations that pending for role holder
+     * removal per each user.
+     *
+     * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo)
+     * @see #addToPendingRoleHolderRemoval(AssociationInfo)
+     * @see #removeFromPendingRoleHolderRemoval(AssociationInfo)
+     * @see #getPendingRoleHolderRemovalAssociationsForUser(int)
+     */
+    @GuardedBy("mRevokedAssociationsPendingRoleHolderRemoval")
+    private final PerUserAssociationSet mRevokedAssociationsPendingRoleHolderRemoval =
+            new PerUserAssociationSet();
+    /**
+     * Contains uid-s of packages pending to be removed from the role holder list (after
+     * revocation of an association), which will happen one the package is no longer visible to the
+     * user.
+     * For quicker uid -> (userId, packageName) look-up this is not a {@code Set<Integer>} but
+     * a {@code Map<Integer, String>} which maps uid-s to packageName-s (userId-s can be derived
+     * from uid-s using {@link UserHandle#getUserId(int)}).
+     *
+     * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo)
+     * @see #addToPendingRoleHolderRemoval(AssociationInfo)
+     * @see #removeFromPendingRoleHolderRemoval(AssociationInfo)
+     */
+    @GuardedBy("mRevokedAssociationsPendingRoleHolderRemoval")
+    private final Map<Integer, String> mUidsPendingRoleHolderRemoval = new HashMap<>();
+
+    AssociationRevokeProcessor(@NonNull CompanionDeviceManagerService service,
+            @NonNull AssociationStoreImpl associationStore,
+            @NonNull PackageManagerInternal packageManager,
+            @NonNull CompanionDevicePresenceMonitor devicePresenceMonitor,
+            @NonNull CompanionApplicationController applicationController,
+            @NonNull SystemDataTransferRequestStore systemDataTransferRequestStore) {
+        mService = service;
+        mContext = service.getContext();
+        mActivityManager = mContext.getSystemService(ActivityManager.class);
+        mAssociationStore = associationStore;
+        mPackageManagerInternal = packageManager;
+        mOnPackageVisibilityChangeListener =
+                new OnPackageVisibilityChangeListener(mActivityManager);
+        mDevicePresenceMonitor = devicePresenceMonitor;
+        mCompanionAppController = applicationController;
+        mSystemDataTransferRequestStore = systemDataTransferRequestStore;
+    }
+
+    // TODO: also revoke notification access
+    void disassociateInternal(int associationId) {
+        final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
+        final int userId = association.getUserId();
+        final String packageName = association.getPackageName();
+        final String deviceProfile = association.getDeviceProfile();
+
+        if (!maybeRemoveRoleHolderForAssociation(association)) {
+            // Need to remove the app from list of the role holders, but will have to do it later
+            // (the app is in foreground at the moment).
+            addToPendingRoleHolderRemoval(association);
+        }
+
+        // Need to check if device still present now because CompanionDevicePresenceMonitor will
+        // remove current connected device after mAssociationStore.removeAssociation
+        final boolean wasPresent = mDevicePresenceMonitor.isDevicePresent(associationId);
+
+        // Removing the association.
+        mAssociationStore.removeAssociation(associationId);
+        // Do not need to persistUserState since CompanionDeviceManagerService will get callback
+        // from #onAssociationChanged, and it will handle the persistUserState which including
+        // active and revoked association.
+        logRemoveAssociation(deviceProfile);
+
+        // Remove all the system data transfer requests for the association.
+        mSystemDataTransferRequestStore.removeRequestsByAssociationId(userId, associationId);
+
+        if (!wasPresent || !association.isNotifyOnDeviceNearby()) return;
+        // The device was connected and the app was notified: check if we need to unbind the app
+        // now.
+        final boolean shouldStayBound = any(
+                mAssociationStore.getAssociationsForPackage(userId, packageName),
+                it -> it.isNotifyOnDeviceNearby()
+                        && mDevicePresenceMonitor.isDevicePresent(it.getId()));
+        if (shouldStayBound) return;
+        mCompanionAppController.unbindCompanionApplication(userId, packageName);
+    }
+
+    /**
+     * First, checks if the companion application should be removed from the list role holders when
+     * upon association's removal, i.e.: association's profile (matches the role) is not null,
+     * the application does not have other associations with the same profile, etc.
+     *
+     * <p>
+     * Then, if establishes that the application indeed has to be removed from the list of the role
+     * holders, checks if it could be done right now -
+     * {@link android.app.role.RoleManager#removeRoleHolderAsUser(String, String, int, UserHandle, java.util.concurrent.Executor, java.util.function.Consumer) RoleManager#removeRoleHolderAsUser()}
+     * will kill the application's process, which leads poor user experience if the application was
+     * in foreground when this happened, to avoid this CDMS delays invoking
+     * {@code RoleManager.removeRoleHolderAsUser()} until the app is no longer in foreground.
+     *
+     * @return {@code true} if the application does NOT need be removed from the list of the role
+     *         holders OR if the application was successfully removed from the list of role holders.
+     *         I.e.: from the role-management perspective the association is done with.
+     *         {@code false} if the application needs to be removed from the list of role the role
+     *         holders, BUT it CDMS would prefer to do it later.
+     *         I.e.: application is in the foreground at the moment, but invoking
+     *         {@code RoleManager.removeRoleHolderAsUser()} will kill the application's process,
+     *         which would lead to the poor UX, hence need to try later.
+     */
+    boolean maybeRemoveRoleHolderForAssociation(@NonNull AssociationInfo association) {
+        if (DEBUG) Log.d(TAG, "maybeRemoveRoleHolderForAssociation() association=" + association);
+        final String deviceProfile = association.getDeviceProfile();
+
+        if (deviceProfile == null) {
+            // No role was granted to for this association, there is nothing else we need to here.
+            return true;
+        }
+        // Do not need to remove the system role since it was pre-granted by the system.
+        if (deviceProfile.equals(DEVICE_PROFILE_AUTOMOTIVE_PROJECTION)) {
+            return true;
+        }
+
+        // Check if the applications is associated with another devices with the profile. If so,
+        // it should remain the role holder.
+        final int id = association.getId();
+        final int userId = association.getUserId();
+        final String packageName = association.getPackageName();
+        final boolean roleStillInUse = any(
+                mAssociationStore.getAssociationsForPackage(userId, packageName),
+                it -> deviceProfile.equals(it.getDeviceProfile()) && id != it.getId());
+        if (roleStillInUse) {
+            // Application should remain a role holder, there is nothing else we need to here.
+            return true;
+        }
+
+        final int packageProcessImportance = getPackageProcessImportance(userId, packageName);
+        if (packageProcessImportance <= IMPORTANCE_VISIBLE) {
+            // Need to remove the app from the list of role holders, but the process is visible to
+            // the user at the moment, so we'll need to it later: log and return false.
+            Slog.i(TAG, "Cannot remove role holder for the removed association id=" + id
+                    + " now - process is visible.");
+            return false;
+        }
+
+        removeRoleHolderForAssociation(mContext, association.getUserId(),
+                association.getPackageName(), association.getDeviceProfile());
+        return true;
+    }
+
+    @SuppressLint("MissingPermission")
+    private int  getPackageProcessImportance(@UserIdInt int userId, @NonNull String packageName) {
+        return Binder.withCleanCallingIdentity(() -> {
+            final int uid =
+                    mPackageManagerInternal.getPackageUid(packageName, /* flags */0, userId);
+            return mActivityManager.getUidImportance(uid);
+        });
+    }
+
+    /**
+     * Set revoked flag for active association and add the revoked association and the uid into
+     * the caches.
+     *
+     * @see #mRevokedAssociationsPendingRoleHolderRemoval
+     * @see #mUidsPendingRoleHolderRemoval
+     * @see OnPackageVisibilityChangeListener
+     */
+    void addToPendingRoleHolderRemoval(@NonNull AssociationInfo association) {
+        // First: set revoked flag
+        association = (new AssociationInfo.Builder(association)).setRevoked(true).build();
+        final String packageName = association.getPackageName();
+        final int userId = association.getUserId();
+        final int uid = mPackageManagerInternal.getPackageUid(packageName, /* flags */0, userId);
+        // Second: add to the set.
+        synchronized (mRevokedAssociationsPendingRoleHolderRemoval) {
+            mRevokedAssociationsPendingRoleHolderRemoval.forUser(association.getUserId())
+                    .add(association);
+            if (!mUidsPendingRoleHolderRemoval.containsKey(uid)) {
+                mUidsPendingRoleHolderRemoval.put(uid, packageName);
+
+                if (mUidsPendingRoleHolderRemoval.size() == 1) {
+                    // Just added first uid: start the listener
+                    mOnPackageVisibilityChangeListener.startListening();
+                }
+            }
+        }
+    }
+
+    /**
+     * Remove the revoked association from the cache and also remove the uid from the map if
+     * there are other associations with the same package still pending for role holder removal.
+     *
+     * @see #mRevokedAssociationsPendingRoleHolderRemoval
+     * @see #mUidsPendingRoleHolderRemoval
+     * @see OnPackageVisibilityChangeListener
+     */
+    private void removeFromPendingRoleHolderRemoval(@NonNull AssociationInfo association) {
+        final String packageName = association.getPackageName();
+        final int userId = association.getUserId();
+        final int uid = mPackageManagerInternal.getPackageUid(packageName, /* flags */  0, userId);
+
+        synchronized (mRevokedAssociationsPendingRoleHolderRemoval) {
+            mRevokedAssociationsPendingRoleHolderRemoval.forUser(userId)
+                    .remove(association);
+
+            final boolean shouldKeepUidForRemoval = any(
+                    getPendingRoleHolderRemovalAssociationsForUser(userId),
+                    ai -> packageName.equals(ai.getPackageName()));
+            // Do not remove the uid from the map since other associations with
+            // the same packageName still pending for role holder removal.
+            if (!shouldKeepUidForRemoval) {
+                mUidsPendingRoleHolderRemoval.remove(uid);
+            }
+
+            if (mUidsPendingRoleHolderRemoval.isEmpty()) {
+                // The set is empty now - can "turn off" the listener.
+                mOnPackageVisibilityChangeListener.stopListening();
+            }
+        }
+    }
+
+    /**
+     * @return a copy of the revoked associations set (safeguarding against
+     *         {@code ConcurrentModificationException}-s).
+     */
+    @NonNull Set<AssociationInfo> getPendingRoleHolderRemovalAssociationsForUser(
+            @UserIdInt int userId) {
+        synchronized (mRevokedAssociationsPendingRoleHolderRemoval) {
+            // Return a copy.
+            return new ArraySet<>(mRevokedAssociationsPendingRoleHolderRemoval.forUser(userId));
+        }
+    }
+
+    private String getPackageNameByUid(int uid) {
+        synchronized (mRevokedAssociationsPendingRoleHolderRemoval) {
+            return mUidsPendingRoleHolderRemoval.get(uid);
+        }
+    }
+
+    /**
+     * An OnUidImportanceListener class which watches the importance of the packages.
+     * In this class, we ONLY interested in the importance of the running process is greater than
+     * {@link ActivityManager.RunningAppProcessInfo#IMPORTANCE_VISIBLE} for the uids have been added
+     * into the {@link #mUidsPendingRoleHolderRemoval}. Lastly remove the role holder for the
+     * revoked associations for the same packages.
+     *
+     * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo)
+     * @see #removeFromPendingRoleHolderRemoval(AssociationInfo)
+     * @see #getPendingRoleHolderRemovalAssociationsForUser(int)
+     */
+    private class OnPackageVisibilityChangeListener implements
+            ActivityManager.OnUidImportanceListener {
+        final @NonNull ActivityManager mAm;
+
+        OnPackageVisibilityChangeListener(@NonNull ActivityManager am) {
+            this.mAm = am;
+        }
+
+        @SuppressLint("MissingPermission")
+        void startListening() {
+            Binder.withCleanCallingIdentity(
+                    () -> mAm.addOnUidImportanceListener(
+                            /* listener */ OnPackageVisibilityChangeListener.this,
+                            ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE));
+        }
+
+        @SuppressLint("MissingPermission")
+        void stopListening() {
+            Binder.withCleanCallingIdentity(
+                    () -> mAm.removeOnUidImportanceListener(
+                            /* listener */ OnPackageVisibilityChangeListener.this));
+        }
+
+        @Override
+        public void onUidImportance(int uid, int importance) {
+            if (importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
+                // The lower the importance value the more "important" the process is.
+                // We are only interested when the process ceases to be visible.
+                return;
+            }
+
+            final String packageName = getPackageNameByUid(uid);
+            if (packageName == null) {
+                // Not interested in this uid.
+                return;
+            }
+
+            final int userId = UserHandle.getUserId(uid);
+
+            boolean needToPersistStateForUser = false;
+
+            for (AssociationInfo association :
+                    getPendingRoleHolderRemovalAssociationsForUser(userId)) {
+                if (!packageName.equals(association.getPackageName())) continue;
+
+                if (!maybeRemoveRoleHolderForAssociation(association)) {
+                    // Did not remove the role holder, will have to try again later.
+                    continue;
+                }
+
+                removeFromPendingRoleHolderRemoval(association);
+                needToPersistStateForUser = true;
+            }
+
+            if (needToPersistStateForUser) {
+                mService.postPersistUserState(userId);
+            }
+        }
+    }
+}
diff --git a/services/companion/java/com/android/server/companion/CompanionApplicationController.java b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
index af0777c..559ebbc 100644
--- a/services/companion/java/com/android/server/companion/CompanionApplicationController.java
+++ b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
@@ -38,6 +38,9 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.infra.PerUser;
 import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
+import com.android.server.companion.presence.ObservableUuid;
+import com.android.server.companion.presence.ObservableUuidStore;
+import com.android.server.companion.utils.PackageUtils;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -61,7 +64,7 @@
  * <ul>
  * <li> {@link #bindCompanionApplication(int, String, boolean)}
  * <li> {@link #unbindCompanionApplication(int, String)}
- * <li> {@link #notifyCompanionApplicationDevicePresenceEvent(AssociationInfo, int)}
+ * <li> {@link #notifyCompanionDevicePresenceEvent(AssociationInfo, int)}
  * <li> {@link #isCompanionApplicationBound(int, String)}
  * <li> {@link #isRebindingCompanionApplicationScheduled(int, String)}
  * </ul>
@@ -251,7 +254,13 @@
         serviceConnector.connect();
     }
 
-    void notifyCompanionApplicationDeviceAppeared(AssociationInfo association) {
+    /**
+     * Notify the app that the device appeared.
+     *
+     * @deprecated use {@link #notifyCompanionDevicePresenceEvent(AssociationInfo, int)} instead
+     */
+    @Deprecated
+    public void notifyCompanionApplicationDeviceAppeared(AssociationInfo association) {
         final int userId = association.getUserId();
         final String packageName = association.getPackageName();
 
@@ -273,7 +282,13 @@
         primaryServiceConnector.postOnDeviceAppeared(association);
     }
 
-    void notifyCompanionApplicationDeviceDisappeared(AssociationInfo association) {
+    /**
+     * Notify the app that the device disappeared.
+     *
+     * @deprecated use {@link #notifyCompanionDevicePresenceEvent(AssociationInfo, int)} instead
+     */
+    @Deprecated
+    public void notifyCompanionApplicationDeviceDisappeared(AssociationInfo association) {
         final int userId = association.getUserId();
         final String packageName = association.getPackageName();
 
@@ -295,7 +310,10 @@
         primaryServiceConnector.postOnDeviceDisappeared(association);
     }
 
-    void notifyCompanionApplicationDevicePresenceEvent(AssociationInfo association, int event) {
+    /**
+     * Notify the app that the device appeared.
+     */
+    public void notifyCompanionDevicePresenceEvent(AssociationInfo association, int event) {
         final int userId = association.getUserId();
         final String packageName = association.getPackageName();
         final CompanionDeviceServiceConnector primaryServiceConnector =
@@ -318,7 +336,10 @@
         primaryServiceConnector.postOnDevicePresenceEvent(devicePresenceEvent);
     }
 
-    void notifyApplicationDevicePresenceEvent(ObservableUuid uuid, int event) {
+    /**
+     * Notify the app that the device disappeared.
+     */
+    public void notifyUuidDevicePresenceEvent(ObservableUuid uuid, int event) {
         final int userId = uuid.getUserId();
         final ParcelUuid parcelUuid = uuid.getUuid();
         final String packageName = uuid.getPackageName();
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index ba1f51b..17ba073 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -22,7 +22,6 @@
 import static android.Manifest.permission.MANAGE_COMPANION_DEVICES;
 import static android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE;
 import static android.Manifest.permission.USE_COMPANION_TRANSPORTS;
-import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
 import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
 import static android.companion.DevicePresenceEvent.EVENT_BLE_APPEARED;
 import static android.companion.DevicePresenceEvent.EVENT_BLE_DISAPPEARED;
@@ -39,17 +38,15 @@
 import static com.android.internal.util.Preconditions.checkState;
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 import static com.android.server.companion.AssociationStore.CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED;
-import static com.android.server.companion.MetricUtils.logRemoveAssociation;
-import static com.android.server.companion.PackageUtils.isRestrictedSettingsAllowed;
-import static com.android.server.companion.PackageUtils.enforceUsesCompanionDeviceFeature;
-import static com.android.server.companion.PackageUtils.getPackageInfo;
-import static com.android.server.companion.PermissionsUtils.checkCallerCanManageCompanionDevice;
-import static com.android.server.companion.PermissionsUtils.enforceCallerCanManageAssociationsForPackage;
-import static com.android.server.companion.PermissionsUtils.enforceCallerCanObservingDevicePresenceByUuid;
-import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOr;
-import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOrCanInteractWithUserId;
-import static com.android.server.companion.PermissionsUtils.sanitizeWithCallerChecks;
-import static com.android.server.companion.RolesUtils.removeRoleHolderForAssociation;
+import static com.android.server.companion.utils.PackageUtils.isRestrictedSettingsAllowed;
+import static com.android.server.companion.utils.PackageUtils.enforceUsesCompanionDeviceFeature;
+import static com.android.server.companion.utils.PackageUtils.getPackageInfo;
+import static com.android.server.companion.utils.PermissionsUtils.checkCallerCanManageCompanionDevice;
+import static com.android.server.companion.utils.PermissionsUtils.enforceCallerCanManageAssociationsForPackage;
+import static com.android.server.companion.utils.PermissionsUtils.enforceCallerCanObservingDevicePresenceByUuid;
+import static com.android.server.companion.utils.PermissionsUtils.enforceCallerIsSystemOr;
+import static com.android.server.companion.utils.PermissionsUtils.enforceCallerIsSystemOrCanInteractWithUserId;
+import static com.android.server.companion.utils.PermissionsUtils.sanitizeWithCallerChecks;
 
 import static java.util.Objects.requireNonNull;
 import static java.util.concurrent.TimeUnit.DAYS;
@@ -61,7 +58,6 @@
 import android.annotation.SuppressLint;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
-import android.app.ActivityManager.RunningAppProcessInfo;
 import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.NotificationManager;
@@ -127,6 +123,8 @@
 import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncController;
 import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncControllerCallback;
 import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
+import com.android.server.companion.presence.ObservableUuid;
+import com.android.server.companion.presence.ObservableUuidStore;
 import com.android.server.companion.transport.CompanionTransportManager;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.wm.ActivityTaskManagerInternal;
@@ -149,7 +147,7 @@
     static final String TAG = "CDM_CompanionDeviceManagerService";
     static final boolean DEBUG = false;
 
-    /** Range of Association IDs allocated for a user.*/
+    /** Range of Association IDs allocated for a user. */
     private static final int ASSOCIATIONS_IDS_PER_USER_RANGE = 100000;
     private static final long PAIR_WITHOUT_PROMPT_WINDOW_MS = 10 * 60 * 1000; // 10 min
 
@@ -162,8 +160,6 @@
     private static final int MAX_CN_LENGTH = 500;
 
     private final ActivityManager mActivityManager;
-    private final OnPackageVisibilityChangeListener mOnPackageVisibilityChangeListener;
-
     private PersistentDataStore mPersistentStore;
     private final PersistUserStateHandler mUserPersistenceHandler;
 
@@ -175,6 +171,7 @@
     private CompanionDevicePresenceMonitor mDevicePresenceMonitor;
     private CompanionApplicationController mCompanionAppController;
     private CompanionTransportManager mTransportManager;
+    private AssociationRevokeProcessor mAssociationRevokeProcessor;
 
     private final ActivityTaskManagerInternal mAtmInternal;
     private final ActivityManagerInternal mAmInternal;
@@ -193,33 +190,6 @@
     @GuardedBy("mPreviouslyUsedIds")
     private final SparseArray<Map<String, Set<Integer>>> mPreviouslyUsedIds = new SparseArray<>();
 
-    /**
-     * A structure that consists of a set of revoked associations that pending for role holder
-     * removal per each user.
-     *
-     * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo)
-     * @see #addToPendingRoleHolderRemoval(AssociationInfo)
-     * @see #removeFromPendingRoleHolderRemoval(AssociationInfo)
-     * @see #getPendingRoleHolderRemovalAssociationsForUser(int)
-     */
-    @GuardedBy("mRevokedAssociationsPendingRoleHolderRemoval")
-    private final PerUserAssociationSet mRevokedAssociationsPendingRoleHolderRemoval =
-            new PerUserAssociationSet();
-    /**
-     * Contains uid-s of packages pending to be removed from the role holder list (after
-     * revocation of an association), which will happen one the package is no longer visible to the
-     * user.
-     * For quicker uid -> (userId, packageName) look-up this is not a {@code Set<Integer>} but
-     * a {@code Map<Integer, String>} which maps uid-s to packageName-s (userId-s can be derived
-     * from uid-s using {@link UserHandle#getUserId(int)}).
-     *
-     * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo)
-     * @see #addToPendingRoleHolderRemoval(AssociationInfo)
-     * @see #removeFromPendingRoleHolderRemoval(AssociationInfo)
-     */
-    @GuardedBy("mRevokedAssociationsPendingRoleHolderRemoval")
-    private final Map<Integer, String> mUidsPendingRoleHolderRemoval = new HashMap<>();
-
     private final RemoteCallbackList<IOnAssociationsChangedListener> mListeners =
             new RemoteCallbackList<>();
 
@@ -243,8 +213,6 @@
         mAssociationStore = new AssociationStoreImpl();
         mSystemDataTransferRequestStore = new SystemDataTransferRequestStore();
 
-        mOnPackageVisibilityChangeListener =
-                new OnPackageVisibilityChangeListener(mActivityManager);
         mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
         mObservableUuidStore = new ObservableUuidStore();
     }
@@ -260,8 +228,6 @@
                 /* cdmService */ this, mAssociationStore, mPersistentStore,
                 mSystemDataTransferRequestStore, mAssociationRequestsProcessor);
 
-        loadAssociationsFromDisk();
-
         mObservableUuidStore.getObservableUuidsForUser(getContext().getUserId());
 
         mAssociationStore.registerListener(mAssociationStoreChangeListener);
@@ -272,10 +238,18 @@
         mCompanionAppController = new CompanionApplicationController(
                 context, mAssociationStore, mObservableUuidStore, mDevicePresenceMonitor,
                 mPowerManagerInternal);
+
+        mAssociationRevokeProcessor = new AssociationRevokeProcessor(this, mAssociationStore,
+                mPackageManagerInternal, mDevicePresenceMonitor, mCompanionAppController,
+                mSystemDataTransferRequestStore);
+
+        loadAssociationsFromDisk();
+
         mTransportManager = new CompanionTransportManager(context, mAssociationStore);
         mSystemDataTransferProcessor = new SystemDataTransferProcessor(this,
                 mPackageManagerInternal, mAssociationStore,
                 mSystemDataTransferRequestStore, mTransportManager);
+
         // TODO(b/279663946): move context sync to a dedicated system service
         mCrossDeviceSyncController = new CrossDeviceSyncController(getContext(), mTransportManager);
 
@@ -307,12 +281,13 @@
                 mBackupRestoreProcessor.addToPendingAppInstall(association);
             } else if (!association.isRevoked()) {
                 activeAssociations.add(association);
-            } else if (maybeRemoveRoleHolderForAssociation(association)) {
+            } else if (mAssociationRevokeProcessor.maybeRemoveRoleHolderForAssociation(
+                    association)) {
                 // Nothing more to do here, but we'll need to persist all the associations to the
                 // disk afterwards.
                 usersToPersistStateFor.add(association.getUserId());
             } else {
-                addToPendingRoleHolderRemoval(association);
+                mAssociationRevokeProcessor.addToPendingRoleHolderRemoval(association);
             }
         }
 
@@ -374,7 +349,7 @@
                 final List<ParcelUuid> deviceUuids = ArrayUtils.isEmpty(bluetoothDeviceUuids)
                         ? Collections.emptyList() : Arrays.asList(bluetoothDeviceUuids);
 
-                for (AssociationInfo ai:
+                for (AssociationInfo ai :
                         mAssociationStore.getAssociationsByAddress(bluetoothDevice.getAddress())) {
                     Slog.i(TAG, "onUserUnlocked, device id( " + ai.getId() + " ) is connected");
                     mDevicePresenceMonitor.onBluetoothCompanionDeviceConnected(ai.getId());
@@ -465,7 +440,7 @@
 
                 bindApplicationIfNeeded(association);
 
-                mCompanionAppController.notifyCompanionApplicationDevicePresenceEvent(
+                mCompanionAppController.notifyCompanionDevicePresenceEvent(
                         association, event);
                 break;
             case EVENT_BLE_DISAPPEARED:
@@ -476,7 +451,7 @@
                     return;
                 }
                 if (association.shouldBindWhenPresent()) {
-                    mCompanionAppController.notifyCompanionApplicationDevicePresenceEvent(
+                    mCompanionAppController.notifyCompanionDevicePresenceEvent(
                             association, event);
                 }
                 // Check if there are other devices associated to the app that are present.
@@ -495,7 +470,7 @@
         final String packageName = uuid.getPackageName();
         final int userId = uuid.getUserId();
 
-        switch(event) {
+        switch (event) {
             case EVENT_BT_CONNECTED:
                 if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
                     mCompanionAppController.bindCompanionApplication(
@@ -505,7 +480,7 @@
                     Log.i(TAG, "u" + userId + "\\" + packageName + " is already bound");
                 }
 
-                mCompanionAppController.notifyApplicationDevicePresenceEvent(uuid, event);
+                mCompanionAppController.notifyUuidDevicePresenceEvent(uuid, event);
 
                 break;
             case EVENT_BT_DISCONNECTED:
@@ -514,7 +489,7 @@
                     return;
                 }
 
-                mCompanionAppController.notifyApplicationDevicePresenceEvent(uuid, event);
+                mCompanionAppController.notifyUuidDevicePresenceEvent(uuid, event);
                 // Check if there are other devices associated to the app or the UUID to be
                 // observed are present.
                 if (shouldBindPackage(userId, packageName)) return;
@@ -544,8 +519,8 @@
 
     /**
      * @return whether the package should be bound (i.e. at least one of the devices associated with
-     *         the package is currently present OR the UUID to be observed by this package is
-     *         currently present).
+     * the package is currently present OR the UUID to be observed by this package is
+     * currently present).
      */
     private boolean shouldBindPackage(@UserIdInt int userId, @NonNull String packageName) {
         final List<AssociationInfo> packageAssociations =
@@ -599,7 +574,8 @@
         allAssociations = new ArrayList<>(
                 mAssociationStore.getAssociationsForUser(userId));
         // ... and add the revoked (removed) association, that are yet to be permanently removed.
-        allAssociations.addAll(getPendingRoleHolderRemovalAssociationsForUser(userId));
+        allAssociations.addAll(
+                mAssociationRevokeProcessor.getPendingRoleHolderRemovalAssociationsForUser(userId));
         // ... and add the restored associations that are pending missing package installation.
         allAssociations.addAll(mBackupRestoreProcessor
                 .getAssociationsPendingAppInstallForUser(userId));
@@ -654,7 +630,7 @@
         }
         // Clear role holders
         for (AssociationInfo association : associationsForPackage) {
-            maybeRemoveRoleHolderForAssociation(association);
+            mAssociationRevokeProcessor.maybeRemoveRoleHolderForAssociation(association);
         }
         // Clear the uuids to be observed.
         for (ObservableUuid uuid : uuidsTobeObserved) {
@@ -712,7 +688,7 @@
             final int id = association.getId();
 
             Slog.i(TAG, "Removing inactive self-managed association id=" + id);
-            disassociateInternal(id);
+            mAssociationRevokeProcessor.disassociateInternal(id);
         }
     }
 
@@ -857,7 +833,7 @@
 
             final AssociationInfo association =
                     getAssociationWithCallerChecks(userId, packageName, deviceMacAddress);
-            disassociateInternal(association.getId());
+            mAssociationRevokeProcessor.disassociateInternal(association.getId());
         }
 
         @Override
@@ -866,7 +842,7 @@
 
             final AssociationInfo association =
                     getAssociationWithCallerChecks(associationId);
-            disassociateInternal(association.getId());
+            mAssociationRevokeProcessor.disassociateInternal(association.getId());
         }
 
         @Override
@@ -902,9 +878,9 @@
         }
 
         /**
-        * @deprecated Use
-        * {@link NotificationManager#isNotificationListenerAccessGranted(ComponentName)} instead.
-        */
+         * @deprecated Use
+         * {@link NotificationManager#isNotificationListenerAccessGranted(ComponentName)} instead.
+         */
         @Deprecated
         @Override
         public boolean hasNotificationAccess(ComponentName component) throws RemoteException {
@@ -1300,7 +1276,7 @@
             return new CompanionDeviceShellCommand(CompanionDeviceManagerService.this,
                     mAssociationStore, mDevicePresenceMonitor, mTransportManager,
                     mSystemDataTransferProcessor, mAssociationRequestsProcessor,
-                    mBackupRestoreProcessor)
+                    mBackupRestoreProcessor, mAssociationRevokeProcessor)
                     .exec(this, in.getFileDescriptor(), out.getFileDescriptor(),
                             err.getFileDescriptor(), args);
         }
@@ -1381,7 +1357,7 @@
             // another association by the time when it is activated from the package installation.
             final Set<AssociationInfo> pendingAssociations = mBackupRestoreProcessor
                     .getAssociationsPendingAppInstallForUser(userId);
-            for (AssociationInfo it: pendingAssociations) {
+            for (AssociationInfo it : pendingAssociations) {
                 usedIds.put(it.getId(), true);
             }
 
@@ -1407,198 +1383,6 @@
         }
     }
 
-    // TODO: also revoke notification access
-    void disassociateInternal(int associationId) {
-        final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
-        final int userId = association.getUserId();
-        final String packageName = association.getPackageName();
-        final String deviceProfile = association.getDeviceProfile();
-
-        if (!maybeRemoveRoleHolderForAssociation(association)) {
-            // Need to remove the app from list of the role holders, but will have to do it later
-            // (the app is in foreground at the moment).
-            addToPendingRoleHolderRemoval(association);
-        }
-
-        // Need to check if device still present now because CompanionDevicePresenceMonitor will
-        // remove current connected device after mAssociationStore.removeAssociation
-        final boolean wasPresent = mDevicePresenceMonitor.isDevicePresent(associationId);
-
-        // Removing the association.
-        mAssociationStore.removeAssociation(associationId);
-        // Do not need to persistUserState since CompanionDeviceManagerService will get callback
-        // from #onAssociationChanged, and it will handle the persistUserState which including
-        // active and revoked association.
-        logRemoveAssociation(deviceProfile);
-
-        // Remove all the system data transfer requests for the association.
-        mSystemDataTransferRequestStore.removeRequestsByAssociationId(userId, associationId);
-
-        if (!wasPresent || !association.isNotifyOnDeviceNearby()) return;
-        // The device was connected and the app was notified: check if we need to unbind the app
-        // now.
-        final boolean shouldStayBound = any(
-                mAssociationStore.getAssociationsForPackage(userId, packageName),
-                it -> it.isNotifyOnDeviceNearby()
-                        && mDevicePresenceMonitor.isDevicePresent(it.getId()));
-        if (shouldStayBound) return;
-        mCompanionAppController.unbindCompanionApplication(userId, packageName);
-    }
-
-    /**
-     * First, checks if the companion application should be removed from the list role holders when
-     * upon association's removal, i.e.: association's profile (matches the role) is not null,
-     * the application does not have other associations with the same profile, etc.
-     *
-     * <p>
-     * Then, if establishes that the application indeed has to be removed from the list of the role
-     * holders, checks if it could be done right now -
-     * {@link android.app.role.RoleManager#removeRoleHolderAsUser(String, String, int, UserHandle, java.util.concurrent.Executor, java.util.function.Consumer) RoleManager#removeRoleHolderAsUser()}
-     * will kill the application's process, which leads poor user experience if the application was
-     * in foreground when this happened, to avoid this CDMS delays invoking
-     * {@code RoleManager.removeRoleHolderAsUser()} until the app is no longer in foreground.
-     *
-     * @return {@code true} if the application does NOT need be removed from the list of the role
-     *         holders OR if the application was successfully removed from the list of role holders.
-     *         I.e.: from the role-management perspective the association is done with.
-     *         {@code false} if the application needs to be removed from the list of role the role
-     *         holders, BUT it CDMS would prefer to do it later.
-     *         I.e.: application is in the foreground at the moment, but invoking
-     *         {@code RoleManager.removeRoleHolderAsUser()} will kill the application's process,
-     *         which would lead to the poor UX, hence need to try later.
-     */
-
-    private boolean maybeRemoveRoleHolderForAssociation(@NonNull AssociationInfo association) {
-        if (DEBUG) Log.d(TAG, "maybeRemoveRoleHolderForAssociation() association=" + association);
-
-        final String deviceProfile = association.getDeviceProfile();
-        if (deviceProfile == null) {
-            // No role was granted to for this association, there is nothing else we need to here.
-            return true;
-        }
-        // Do not need to remove the system role since it was pre-granted by the system.
-        if (deviceProfile.equals(DEVICE_PROFILE_AUTOMOTIVE_PROJECTION)) {
-            return true;
-        }
-
-        // Check if the applications is associated with another devices with the profile. If so,
-        // it should remain the role holder.
-        final int id = association.getId();
-        final int userId = association.getUserId();
-        final String packageName = association.getPackageName();
-        final boolean roleStillInUse = any(
-                mAssociationStore.getAssociationsForPackage(userId, packageName),
-                it -> deviceProfile.equals(it.getDeviceProfile()) && id != it.getId());
-        if (roleStillInUse) {
-            // Application should remain a role holder, there is nothing else we need to here.
-            return true;
-        }
-
-        final int packageProcessImportance = getPackageProcessImportance(userId, packageName);
-        if (packageProcessImportance <= IMPORTANCE_VISIBLE) {
-            // Need to remove the app from the list of role holders, but the process is visible to
-            // the user at the moment, so we'll need to it later: log and return false.
-            Slog.i(TAG, "Cannot remove role holder for the removed association id=" + id
-                    + " now - process is visible.");
-            return false;
-        }
-
-        removeRoleHolderForAssociation(getContext(), association);
-        return true;
-    }
-
-    private int getPackageProcessImportance(@UserIdInt int userId, @NonNull String packageName) {
-        return Binder.withCleanCallingIdentity(() -> {
-            final int uid =
-                    mPackageManagerInternal.getPackageUid(packageName, /* flags */0, userId);
-            return mActivityManager.getUidImportance(uid);
-        });
-    }
-
-    /**
-     * Set revoked flag for active association and add the revoked association and the uid into
-     * the caches.
-     *
-     * @see #mRevokedAssociationsPendingRoleHolderRemoval
-     * @see #mUidsPendingRoleHolderRemoval
-     * @see OnPackageVisibilityChangeListener
-     */
-    private void addToPendingRoleHolderRemoval(@NonNull AssociationInfo association) {
-        // First: set revoked flag.
-        association = (new AssociationInfo.Builder(association))
-                .setRevoked(true)
-                .build();
-
-        final String packageName = association.getPackageName();
-        final int userId = association.getUserId();
-        final int uid = mPackageManagerInternal.getPackageUid(packageName, /* flags */0, userId);
-
-        // Second: add to the set.
-        synchronized (mRevokedAssociationsPendingRoleHolderRemoval) {
-            mRevokedAssociationsPendingRoleHolderRemoval.forUser(association.getUserId())
-                    .add(association);
-            if (!mUidsPendingRoleHolderRemoval.containsKey(uid)) {
-                mUidsPendingRoleHolderRemoval.put(uid, packageName);
-
-                if (mUidsPendingRoleHolderRemoval.size() == 1) {
-                    // Just added first uid: start the listener
-                    mOnPackageVisibilityChangeListener.startListening();
-                }
-            }
-        }
-    }
-
-    /**
-     * Remove the revoked association from the cache and also remove the uid from the map if
-     * there are other associations with the same package still pending for role holder removal.
-     *
-     * @see #mRevokedAssociationsPendingRoleHolderRemoval
-     * @see #mUidsPendingRoleHolderRemoval
-     * @see OnPackageVisibilityChangeListener
-     */
-    private void removeFromPendingRoleHolderRemoval(@NonNull AssociationInfo association) {
-        final String packageName = association.getPackageName();
-        final int userId = association.getUserId();
-        final int uid = mPackageManagerInternal.getPackageUid(packageName, /* flags */0, userId);
-
-        synchronized (mRevokedAssociationsPendingRoleHolderRemoval) {
-            mRevokedAssociationsPendingRoleHolderRemoval.forUser(userId)
-                    .remove(association);
-
-            final boolean shouldKeepUidForRemoval = any(
-                    getPendingRoleHolderRemovalAssociationsForUser(userId),
-                    ai -> packageName.equals(ai.getPackageName()));
-            // Do not remove the uid from the map since other associations with
-            // the same packageName still pending for role holder removal.
-            if (!shouldKeepUidForRemoval) {
-                mUidsPendingRoleHolderRemoval.remove(uid);
-            }
-
-            if (mUidsPendingRoleHolderRemoval.isEmpty()) {
-                // The set is empty now - can "turn off" the listener.
-                mOnPackageVisibilityChangeListener.stopListening();
-            }
-        }
-    }
-
-    /**
-     * @return a copy of the revoked associations set (safeguarding against
-     *         {@code ConcurrentModificationException}-s).
-     */
-    private @NonNull Set<AssociationInfo> getPendingRoleHolderRemovalAssociationsForUser(
-            @UserIdInt int userId) {
-        synchronized (mRevokedAssociationsPendingRoleHolderRemoval) {
-            // Return a copy.
-            return new ArraySet<>(mRevokedAssociationsPendingRoleHolderRemoval.forUser(userId));
-        }
-    }
-
-    private String getPackageNameByUid(int uid) {
-        synchronized (mRevokedAssociationsPendingRoleHolderRemoval) {
-            return mUidsPendingRoleHolderRemoval.get(uid);
-        }
-    }
-
     void updateSpecialAccessPermissionForAssociatedPackage(AssociationInfo association) {
         final PackageInfo packageInfo =
                 getPackageInfo(getContext(), association.getUserId(), association.getPackageName());
@@ -1704,11 +1488,11 @@
 
     private final AssociationStore.OnChangeListener mAssociationStoreChangeListener =
             new AssociationStore.OnChangeListener() {
-        @Override
-        public void onAssociationChanged(int changeType, AssociationInfo association) {
-            onAssociationChangedInternal(changeType, association);
-        }
-    };
+                @Override
+                public void onAssociationChanged(int changeType, AssociationInfo association) {
+                    onAssociationChangedInternal(changeType, association);
+                }
+            };
 
     private final CompanionDevicePresenceMonitor.Callback mDevicePresenceCallback =
             new CompanionDevicePresenceMonitor.Callback() {
@@ -1731,7 +1515,7 @@
                 public void onDevicePresenceEventByUuid(ObservableUuid uuid, int event) {
                     onDevicePresenceEventByUuidInternal(uuid, event);
                 }
-    };
+            };
 
     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
         @Override
@@ -1887,73 +1671,8 @@
         }
     }
 
-    /**
-     * An OnUidImportanceListener class which watches the importance of the packages.
-     * In this class, we ONLY interested in the importance of the running process is greater than
-     * {@link RunningAppProcessInfo.IMPORTANCE_VISIBLE} for the uids have been added into the
-     * {@link mUidsPendingRoleHolderRemoval}. Lastly remove the role holder for the revoked
-     * associations for the same packages.
-     *
-     * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo)
-     * @see #removeFromPendingRoleHolderRemoval(AssociationInfo)
-     * @see #getPendingRoleHolderRemovalAssociationsForUser(int)
-     */
-    private class OnPackageVisibilityChangeListener implements
-            ActivityManager.OnUidImportanceListener {
-        final @NonNull ActivityManager mAm;
-
-        OnPackageVisibilityChangeListener(@NonNull ActivityManager am) {
-            this.mAm = am;
-        }
-
-        void startListening() {
-            Binder.withCleanCallingIdentity(
-                    () -> mAm.addOnUidImportanceListener(
-                            /* listener */ OnPackageVisibilityChangeListener.this,
-                            RunningAppProcessInfo.IMPORTANCE_VISIBLE));
-        }
-
-        void stopListening() {
-            Binder.withCleanCallingIdentity(
-                    () -> mAm.removeOnUidImportanceListener(
-                            /* listener */ OnPackageVisibilityChangeListener.this));
-        }
-
-        @Override
-        public void onUidImportance(int uid, int importance) {
-            if (importance <= RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
-                // The lower the importance value the more "important" the process is.
-                // We are only interested when the process ceases to be visible.
-                return;
-            }
-
-            final String packageName = getPackageNameByUid(uid);
-            if (packageName == null) {
-                // Not interested in this uid.
-                return;
-            }
-
-            final int userId = UserHandle.getUserId(uid);
-
-            boolean needToPersistStateForUser = false;
-
-            for (AssociationInfo association :
-                    getPendingRoleHolderRemovalAssociationsForUser(userId)) {
-                if (!packageName.equals(association.getPackageName())) continue;
-
-                if (!maybeRemoveRoleHolderForAssociation(association)) {
-                    // Did not remove the role holder, will have to try again later.
-                    continue;
-                }
-
-                removeFromPendingRoleHolderRemoval(association);
-                needToPersistStateForUser = true;
-            }
-
-            if (needToPersistStateForUser) {
-                mUserPersistenceHandler.postPersistUserState(userId);
-            }
-        }
+    void postPersistUserState(@UserIdInt int userId) {
+        mUserPersistenceHandler.postPersistUserState(userId);
     }
 
     static class PerUserAssociationSet extends PerUser<Set<AssociationInfo>> {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 5663434..74b4cab 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -18,7 +18,7 @@
 
 import static android.companion.CompanionDeviceManager.MESSAGE_REQUEST_CONTEXT_SYNC;
 
-import static com.android.server.companion.PermissionsUtils.sanitizeWithCallerChecks;
+import static com.android.server.companion.utils.PermissionsUtils.sanitizeWithCallerChecks;
 
 import android.companion.AssociationInfo;
 import android.companion.ContextSyncMessage;
@@ -36,6 +36,7 @@
 import com.android.server.companion.datatransfer.contextsync.BitmapUtils;
 import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncController;
 import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
+import com.android.server.companion.presence.ObservableUuid;
 import com.android.server.companion.transport.CompanionTransportManager;
 
 import java.io.PrintWriter;
@@ -45,6 +46,7 @@
     private static final String TAG = "CDM_CompanionDeviceShellCommand";
 
     private final CompanionDeviceManagerService mService;
+    private final AssociationRevokeProcessor mRevokeProcessor;
     private final AssociationStoreImpl mAssociationStore;
     private final CompanionDevicePresenceMonitor mDevicePresenceMonitor;
     private final CompanionTransportManager mTransportManager;
@@ -59,7 +61,8 @@
             CompanionTransportManager transportManager,
             SystemDataTransferProcessor systemDataTransferProcessor,
             AssociationRequestsProcessor associationRequestsProcessor,
-            BackupRestoreProcessor backupRestoreProcessor) {
+            BackupRestoreProcessor backupRestoreProcessor,
+            AssociationRevokeProcessor revokeProcessor) {
         mService = service;
         mAssociationStore = associationStore;
         mDevicePresenceMonitor = devicePresenceMonitor;
@@ -67,6 +70,7 @@
         mSystemDataTransferProcessor = systemDataTransferProcessor;
         mAssociationRequestsProcessor = associationRequestsProcessor;
         mBackupRestoreProcessor = backupRestoreProcessor;
+        mRevokeProcessor = revokeProcessor;
     }
 
     @Override
@@ -126,7 +130,7 @@
                     final AssociationInfo association =
                             mService.getAssociationWithCallerChecks(userId, packageName, address);
                     if (association != null) {
-                        mService.disassociateInternal(association.getId());
+                        mRevokeProcessor.disassociateInternal(association.getId());
                     }
                 }
                 break;
@@ -138,7 +142,7 @@
                             mAssociationStore.getAssociationsForPackage(userId, packageName);
                     for (AssociationInfo association : userAssociations) {
                         if (sanitizeWithCallerChecks(mService.getContext(), association) != null) {
-                            mService.disassociateInternal(association.getId());
+                            mRevokeProcessor.disassociateInternal(association.getId());
                         }
                     }
                 }
diff --git a/services/companion/java/com/android/server/companion/PersistentDataStore.java b/services/companion/java/com/android/server/companion/PersistentDataStore.java
index 1ebe65c..7527efb 100644
--- a/services/companion/java/com/android/server/companion/PersistentDataStore.java
+++ b/services/companion/java/com/android/server/companion/PersistentDataStore.java
@@ -27,11 +27,11 @@
 import static com.android.internal.util.XmlUtils.writeStringAttribute;
 import static com.android.server.companion.CompanionDeviceManagerService.getFirstAssociationIdForUser;
 import static com.android.server.companion.CompanionDeviceManagerService.getLastAssociationIdForUser;
-import static com.android.server.companion.DataStoreUtils.createStorageFileForUser;
-import static com.android.server.companion.DataStoreUtils.fileToByteArray;
-import static com.android.server.companion.DataStoreUtils.isEndOfTag;
-import static com.android.server.companion.DataStoreUtils.isStartOfTag;
-import static com.android.server.companion.DataStoreUtils.writeToFileSafely;
+import static com.android.server.companion.utils.DataStoreUtils.createStorageFileForUser;
+import static com.android.server.companion.utils.DataStoreUtils.fileToByteArray;
+import static com.android.server.companion.utils.DataStoreUtils.isEndOfTag;
+import static com.android.server.companion.utils.DataStoreUtils.isStartOfTag;
+import static com.android.server.companion.utils.DataStoreUtils.writeToFileSafely;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -51,6 +51,7 @@
 import com.android.internal.util.XmlUtils;
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
+import com.android.server.companion.utils.DataStoreUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
index 260b21f..74236a4 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
@@ -23,7 +23,7 @@
 import static android.content.ComponentName.createRelative;
 import static android.content.pm.PackageManager.FEATURE_WATCH;
 
-import static com.android.server.companion.Utils.prepareForIpc;
+import static com.android.server.companion.utils.Utils.prepareForIpc;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -54,9 +54,9 @@
 import com.android.internal.R;
 import com.android.server.companion.AssociationStore;
 import com.android.server.companion.CompanionDeviceManagerService;
-import com.android.server.companion.PackageUtils;
-import com.android.server.companion.PermissionsUtils;
 import com.android.server.companion.transport.CompanionTransportManager;
+import com.android.server.companion.utils.PackageUtils;
+import com.android.server.companion.utils.PermissionsUtils;
 
 import java.util.List;
 import java.util.concurrent.ExecutorService;
diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java
index c4c80f9..ee816a0 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java
@@ -22,11 +22,11 @@
 import static com.android.internal.util.XmlUtils.readIntAttribute;
 import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
 import static com.android.internal.util.XmlUtils.writeIntAttribute;
-import static com.android.server.companion.DataStoreUtils.createStorageFileForUser;
-import static com.android.server.companion.DataStoreUtils.fileToByteArray;
-import static com.android.server.companion.DataStoreUtils.isEndOfTag;
-import static com.android.server.companion.DataStoreUtils.isStartOfTag;
-import static com.android.server.companion.DataStoreUtils.writeToFileSafely;
+import static com.android.server.companion.utils.DataStoreUtils.createStorageFileForUser;
+import static com.android.server.companion.utils.DataStoreUtils.fileToByteArray;
+import static com.android.server.companion.utils.DataStoreUtils.isEndOfTag;
+import static com.android.server.companion.utils.DataStoreUtils.isStartOfTag;
+import static com.android.server.companion.utils.DataStoreUtils.writeToFileSafely;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
diff --git a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
index 7e30790..2899c05 100644
--- a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
+++ b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
@@ -34,7 +34,7 @@
 import static android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_POWER;
 
 import static com.android.server.companion.presence.CompanionDevicePresenceMonitor.DEBUG;
-import static com.android.server.companion.presence.Utils.btDeviceToString;
+import static com.android.server.companion.utils.Utils.btDeviceToString;
 
 import static java.util.Objects.requireNonNull;
 
@@ -168,7 +168,7 @@
     void startScan() {
         enforceInitialized();
 
-        if (DEBUG) Log.i(TAG, "startScan()");
+        Slog.i(TAG, "startBleScan()");
         // This method should not be called if scan is already in progress.
         if (mScanning) {
             Slog.w(TAG, "Scan is already in progress.");
@@ -228,7 +228,7 @@
     void stopScanIfNeeded() {
         enforceInitialized();
 
-        if (DEBUG) Log.i(TAG, "stopScan()");
+        Slog.i(TAG, "stopBleScan()");
         if (!mScanning) {
             if (DEBUG) Log.d(TAG, "  > not scanning.");
             return;
diff --git a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
index c514f3e..0287f62 100644
--- a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
+++ b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
@@ -20,7 +20,7 @@
 import static android.companion.DevicePresenceEvent.EVENT_BT_DISCONNECTED;
 
 import static com.android.server.companion.presence.CompanionDevicePresenceMonitor.DEBUG;
-import static com.android.server.companion.presence.Utils.btDeviceToString;
+import static com.android.server.companion.utils.Utils.btDeviceToString;
 
 import android.annotation.NonNull;
 import android.annotation.SuppressLint;
@@ -40,8 +40,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.companion.AssociationStore;
-import com.android.server.companion.ObservableUuid;
-import com.android.server.companion.ObservableUuidStore;
 
 import java.util.Arrays;
 import java.util.Collections;
diff --git a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
index 54a4692..3da9693 100644
--- a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
+++ b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
@@ -41,10 +41,10 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.server.companion.AssociationStore;
-import com.android.server.companion.ObservableUuid;
-import com.android.server.companion.ObservableUuidStore;
 
 import java.io.PrintWriter;
 import java.util.HashSet;
@@ -102,12 +102,24 @@
     private final @NonNull Set<Integer> mNearbyBleDevices = new HashSet<>();
     private final @NonNull Set<Integer> mReportedSelfManagedDevices = new HashSet<>();
     private final @NonNull Set<ParcelUuid> mConnectedUuidDevices = new HashSet<>();
+    @GuardedBy("mBtDisconnectedDevices")
+    private final @NonNull Set<Integer> mBtDisconnectedDevices = new HashSet<>();
+
+    // A map to track device presence within 10 seconds of Bluetooth disconnection.
+    // The key is the association ID, and the boolean value indicates if the device
+    // was detected again within that time frame.
+    @GuardedBy("mBtDisconnectedDevices")
+    private final @NonNull SparseBooleanArray mBtDisconnectedDevicesBlePresence =
+            new SparseBooleanArray();
 
     // Tracking "simulated" presence. Used for debugging and testing only.
     private final @NonNull Set<Integer> mSimulated = new HashSet<>();
     private final SimulatedDevicePresenceSchedulerHelper mSchedulerHelper =
             new SimulatedDevicePresenceSchedulerHelper();
 
+    private final BleDeviceDisappearedScheduler mBleDeviceDisappearedScheduler =
+            new BleDeviceDisappearedScheduler();
+
     public CompanionDevicePresenceMonitor(UserManager userManager,
             @NonNull AssociationStore associationStore,
             @NonNull ObservableUuidStore observableUuidStore, @NonNull Callback callback) {
@@ -229,13 +241,24 @@
 
     @Override
     public void onBluetoothCompanionDeviceConnected(int associationId) {
-        Slog.i(TAG, "onBluetoothCompanionDeviceConnected: "
-                + "associationId( " + associationId + " )");
-        onDevicePresenceEvent(mConnectedBtDevices, associationId, EVENT_BT_CONNECTED);
-        // Stop scanning for BLE devices when this device is connected
-        // and there are no other devices to connect to.
-        if (canStopBleScan()) {
-            mBleScanner.stopScanIfNeeded();
+        synchronized (mBtDisconnectedDevices) {
+            // A device is considered reconnected within 10 seconds if a pending BLE lost report is
+            // followed by a detected Bluetooth connection.
+            boolean isReconnected = mBtDisconnectedDevices.contains(associationId);
+            if (isReconnected) {
+                Slog.i(TAG, "Device ( " + associationId + " ) is reconnected within 10s.");
+                mBleDeviceDisappearedScheduler.unScheduleDeviceDisappeared(associationId);
+            }
+
+            Slog.i(TAG, "onBluetoothCompanionDeviceConnected: "
+                    + "associationId( " + associationId + " )");
+            onDevicePresenceEvent(mConnectedBtDevices, associationId, EVENT_BT_CONNECTED);
+
+            // Stop the BLE scan if all devices report BT connected status and BLE was present.
+            if (canStopBleScan()) {
+                mBleScanner.stopScanIfNeeded();
+            }
+
         }
     }
 
@@ -247,6 +270,14 @@
         mBleScanner.startScan();
 
         onDevicePresenceEvent(mConnectedBtDevices, associationId, EVENT_BT_DISCONNECTED);
+        // If current device is BLE present but BT is disconnected , means it will be
+        // potentially out of range later. Schedule BLE disappeared callback.
+        if (isBlePresent(associationId)) {
+            synchronized (mBtDisconnectedDevices) {
+                mBtDisconnectedDevices.add(associationId);
+            }
+            mBleDeviceDisappearedScheduler.scheduleBleDeviceDisappeared(associationId);
+        }
     }
 
     @Override
@@ -283,6 +314,12 @@
     @Override
     public void onBleCompanionDeviceFound(int associationId) {
         onDevicePresenceEvent(mNearbyBleDevices, associationId, EVENT_BLE_APPEARED);
+        synchronized (mBtDisconnectedDevices) {
+            final boolean isCurrentPresent = mBtDisconnectedDevicesBlePresence.get(associationId);
+            if (mBtDisconnectedDevices.contains(associationId) && isCurrentPresent) {
+                mBleDeviceDisappearedScheduler.unScheduleDeviceDisappeared(associationId);
+            }
+        }
     }
 
     @Override
@@ -353,6 +390,16 @@
 
         switch (event) {
             case EVENT_BLE_APPEARED:
+                synchronized (mBtDisconnectedDevices) {
+                    // If a BLE device is detected within 10 seconds after BT is disconnected,
+                    // flag it as BLE is present.
+                    if (mBtDisconnectedDevices.contains(associationId)) {
+                        Slog.i(TAG, "Device ( " + associationId + " ) is present,"
+                                + " do not need to send the callback with event ( "
+                                + EVENT_BLE_APPEARED + " ).");
+                        mBtDisconnectedDevicesBlePresence.append(associationId, true);
+                    }
+                }
             case EVENT_BT_CONNECTED:
             case EVENT_SELF_MANAGED_APPEARED:
                 final boolean added = presentDevicesForSource.add(associationId);
@@ -405,6 +452,8 @@
         mNearbyBleDevices.remove(id);
         mReportedSelfManagedDevices.remove(id);
         mSimulated.remove(id);
+        mBtDisconnectedDevices.remove(id);
+        mBtDisconnectedDevicesBlePresence.delete(id);
 
         // Do NOT call mCallback.onDeviceDisappeared()!
         // CompanionDeviceManagerService will know that the association is removed, and will do
@@ -427,14 +476,21 @@
         throw new SecurityException("Caller is neither Shell nor Root");
     }
 
+    /**
+     * The BLE scan can be only stopped if all the devices have been reported
+     * BT connected and BLE presence and are not pending to report BLE lost.
+     */
     private boolean canStopBleScan() {
         for (AssociationInfo ai : mAssociationStore.getAssociations()) {
             int id = ai.getId();
-            // The BLE scan cannot be stopped if there's a device is not yet connected.
-            if (ai.isNotifyOnDeviceNearby() && !isBtConnected(id)) {
-                Slog.i(TAG, "The BLE scan cannot be stopped, "
-                        + "device( " + id + " ) is not yet connected");
-                return false;
+            synchronized (mBtDisconnectedDevices) {
+                if (ai.isNotifyOnDeviceNearby() && !(isBtConnected(id)
+                        && isBlePresent(id) && mBtDisconnectedDevices.isEmpty())) {
+                    Slog.i(TAG, "The BLE scan cannot be stopped, "
+                            + "device( " + id + " ) is not yet connected "
+                            + "OR the BLE is not current present Or is pending to report BLE lost");
+                    return false;
+                }
             }
         }
         return true;
@@ -514,4 +570,51 @@
             }
         }
     }
+
+    private class BleDeviceDisappearedScheduler extends Handler {
+        BleDeviceDisappearedScheduler() {
+            super(Looper.getMainLooper());
+        }
+
+        void scheduleBleDeviceDisappeared(int associationId) {
+            if (hasMessages(associationId)) {
+                removeMessages(associationId);
+            }
+            Slog.i(TAG, "scheduleBleDeviceDisappeared for Device: ( " + associationId + " ).");
+            sendEmptyMessageDelayed(associationId,  10 * 1000 /* 10 seconds */);
+        }
+
+        void unScheduleDeviceDisappeared(int associationId) {
+            if (hasMessages(associationId)) {
+                Slog.i(TAG, "unScheduleDeviceDisappeared for Device( " + associationId + " )");
+                synchronized (mBtDisconnectedDevices) {
+                    mBtDisconnectedDevices.remove(associationId);
+                    mBtDisconnectedDevicesBlePresence.delete(associationId);
+                }
+
+                removeMessages(associationId);
+            }
+        }
+
+        @Override
+        public void handleMessage(@NonNull Message msg) {
+            final int associationId = msg.what;
+            synchronized (mBtDisconnectedDevices) {
+                final boolean isCurrentPresent = mBtDisconnectedDevicesBlePresence.get(
+                        associationId);
+                // If a device hasn't reported after 10 seconds and is not currently present,
+                // assume BLE is lost and trigger the onDeviceEvent callback with the
+                // EVENT_BLE_DISAPPEARED event.
+                if (mBtDisconnectedDevices.contains(associationId)
+                        && !isCurrentPresent) {
+                    Slog.i(TAG, "Device ( " + associationId + " ) is likely BLE out of range, "
+                            + "sending callback with event ( " + EVENT_BLE_DISAPPEARED + " )");
+                    onDevicePresenceEvent(mNearbyBleDevices, associationId, EVENT_BLE_DISAPPEARED);
+                }
+
+                mBtDisconnectedDevices.remove(associationId);
+                mBtDisconnectedDevicesBlePresence.delete(associationId);
+            }
+        }
+    }
 }
diff --git a/services/companion/java/com/android/server/companion/ObservableUuid.java b/services/companion/java/com/android/server/companion/presence/ObservableUuid.java
similarity index 96%
rename from services/companion/java/com/android/server/companion/ObservableUuid.java
rename to services/companion/java/com/android/server/companion/presence/ObservableUuid.java
index 6ab3188..9cfa270 100644
--- a/services/companion/java/com/android/server/companion/ObservableUuid.java
+++ b/services/companion/java/com/android/server/companion/presence/ObservableUuid.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.companion;
+package com.android.server.companion.presence;
 
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
diff --git a/services/companion/java/com/android/server/companion/ObservableUuidStore.java b/services/companion/java/com/android/server/companion/presence/ObservableUuidStore.java
similarity index 93%
rename from services/companion/java/com/android/server/companion/ObservableUuidStore.java
rename to services/companion/java/com/android/server/companion/presence/ObservableUuidStore.java
index 94be22a..ee8b106 100644
--- a/services/companion/java/com/android/server/companion/ObservableUuidStore.java
+++ b/services/companion/java/com/android/server/companion/presence/ObservableUuidStore.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.companion;
+package com.android.server.companion.presence;
 
 import static com.android.internal.util.XmlUtils.readIntAttribute;
 import static com.android.internal.util.XmlUtils.readLongAttribute;
@@ -22,10 +22,10 @@
 import static com.android.internal.util.XmlUtils.writeIntAttribute;
 import static com.android.internal.util.XmlUtils.writeLongAttribute;
 import static com.android.internal.util.XmlUtils.writeStringAttribute;
-import static com.android.server.companion.DataStoreUtils.createStorageFileForUser;
-import static com.android.server.companion.DataStoreUtils.isEndOfTag;
-import static com.android.server.companion.DataStoreUtils.isStartOfTag;
-import static com.android.server.companion.DataStoreUtils.writeToFileSafely;
+import static com.android.server.companion.utils.DataStoreUtils.createStorageFileForUser;
+import static com.android.server.companion.utils.DataStoreUtils.isEndOfTag;
+import static com.android.server.companion.utils.DataStoreUtils.isStartOfTag;
+import static com.android.server.companion.utils.DataStoreUtils.writeToFileSafely;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -57,6 +57,9 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
+/**
+ * This store manages the cache and disk data for observable uuids.
+ */
 public class ObservableUuidStore {
     private static final String TAG = "CDM_ObservableUuidStore";
     private static final String FILE_NAME = "observing_uuids_presence.xml";
@@ -84,9 +87,9 @@
     }
 
     /**
-     * Remove the observable uuid from the disk.
+     * Remove the observable uuid.
      */
-    void removeObservableUuid(@UserIdInt int userId, ParcelUuid uuid, String packageName) {
+    public void removeObservableUuid(@UserIdInt int userId, ParcelUuid uuid, String packageName) {
         List<ObservableUuid> cachedObservableUuids;
 
         synchronized (mLock) {
@@ -101,7 +104,10 @@
         mExecutor.execute(() -> writeObservableUuidToStore(userId, cachedObservableUuids));
     }
 
-    void writeObservableUuid(@UserIdInt int userId, ObservableUuid uuid) {
+    /**
+     * Write the observable uuid.
+     */
+    public void writeObservableUuid(@UserIdInt int userId, ObservableUuid uuid) {
         Slog.i(TAG, "Writing uuid=" + uuid.getUuid() + " to store.");
 
         List<ObservableUuid> cachedObservableUuids;
diff --git a/services/companion/java/com/android/server/companion/presence/Utils.java b/services/companion/java/com/android/server/companion/presence/Utils.java
deleted file mode 100644
index 583b443..0000000
--- a/services/companion/java/com/android/server/companion/presence/Utils.java
+++ /dev/null
@@ -1,49 +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.server.companion.presence;
-
-import android.annotation.NonNull;
-import android.bluetooth.BluetoothDevice;
-
-/** Utilities for working with Bluetooth and BLE devices. */
-class Utils {
-
-    /**
-     * @return short String representation of {@link BluetoothDevice}.
-     */
-    static String btDeviceToString(@NonNull BluetoothDevice btDevice) {
-        final StringBuilder sb = new StringBuilder(btDevice.getAddress());
-
-        sb.append(" [name=");
-        final String name = btDevice.getName();
-        if (name != null) {
-            sb.append('\'').append(name).append('\'');
-        } else {
-            sb.append("null");
-        }
-
-        final String alias = btDevice.getAlias();
-        if (alias != null) {
-            sb.append(", alias='").append(alias).append("'");
-        }
-
-        return sb.append(']').toString();
-    }
-
-    private Utils() {
-    }
-}
diff --git a/services/companion/java/com/android/server/companion/DataStoreUtils.java b/services/companion/java/com/android/server/companion/utils/DataStoreUtils.java
similarity index 97%
rename from services/companion/java/com/android/server/companion/DataStoreUtils.java
rename to services/companion/java/com/android/server/companion/utils/DataStoreUtils.java
index 04ce1f6..c75b1a5 100644
--- a/services/companion/java/com/android/server/companion/DataStoreUtils.java
+++ b/services/companion/java/com/android/server/companion/utils/DataStoreUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.companion;
+package com.android.server.companion.utils;
 
 import static org.xmlpull.v1.XmlPullParser.END_TAG;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -80,7 +80,7 @@
 
     /**
      * Writing to file could fail, for example, if the user has been recently removed and so was
-     * their DE (/data/system_de/<user-id>/) directory.
+     * their DE (/data/system_de/[user-id]/) directory.
      */
     public static void writeToFileSafely(
             @NonNull AtomicFile file, @NonNull ThrowingConsumer<FileOutputStream> consumer) {
diff --git a/services/companion/java/com/android/server/companion/MetricUtils.java b/services/companion/java/com/android/server/companion/utils/MetricUtils.java
similarity index 92%
rename from services/companion/java/com/android/server/companion/MetricUtils.java
rename to services/companion/java/com/android/server/companion/utils/MetricUtils.java
index cf867b6..8ea5c89 100644
--- a/services/companion/java/com/android/server/companion/MetricUtils.java
+++ b/services/companion/java/com/android/server/companion/utils/MetricUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.companion;
+package com.android.server.companion.utils;
 
 import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
 import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
@@ -41,7 +41,7 @@
 
 import java.util.Map;
 
-final class MetricUtils {
+public final class MetricUtils {
 
     private static final Map<String, Integer> METRIC_DEVICE_PROFILE;
     static {
@@ -75,13 +75,19 @@
         METRIC_DEVICE_PROFILE = unmodifiableMap(map);
     }
 
-    static void logCreateAssociation(String profile) {
+    /**
+     * Log association creation
+     */
+    public static void logCreateAssociation(String profile) {
         write(CDM_ASSOCIATION_ACTION,
                 CDM_ASSOCIATION_ACTION__ACTION__CREATED,
                 METRIC_DEVICE_PROFILE.get(profile));
     }
 
-    static void logRemoveAssociation(String profile) {
+    /**
+     * Log association removal
+     */
+    public static void logRemoveAssociation(String profile) {
         write(CDM_ASSOCIATION_ACTION,
                 CDM_ASSOCIATION_ACTION__ACTION__REMOVED,
                 METRIC_DEVICE_PROFILE.get(profile));
diff --git a/services/companion/java/com/android/server/companion/PackageUtils.java b/services/companion/java/com/android/server/companion/utils/PackageUtils.java
similarity index 86%
rename from services/companion/java/com/android/server/companion/PackageUtils.java
rename to services/companion/java/com/android/server/companion/utils/PackageUtils.java
index 3aae1ec..d38590e 100644
--- a/services/companion/java/com/android/server/companion/PackageUtils.java
+++ b/services/companion/java/com/android/server/companion/utils/PackageUtils.java
@@ -14,16 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.server.companion;
+package com.android.server.companion.utils;
 
 import static android.content.pm.PackageManager.FEATURE_COMPANION_DEVICE_SETUP;
 import static android.content.pm.PackageManager.GET_CONFIGURATIONS;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 import static android.os.Binder.getCallingUid;
 
-import static com.android.server.companion.CompanionDeviceManagerService.DEBUG;
-import static com.android.server.companion.CompanionDeviceManagerService.TAG;
-
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -44,13 +41,11 @@
 import android.content.pm.Signature;
 import android.os.Binder;
 import android.os.Process;
-import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.util.ArrayUtils;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -58,16 +53,22 @@
 import java.util.Set;
 
 /**
- * Utility methods for working with {@link PackageInfo}-s.
+ * Utility methods for working with {@link PackageInfo}.
  */
 public final class PackageUtils {
+
+    private static final String TAG = "CDM_PackageUtils";
+
     private static final Intent COMPANION_SERVICE_INTENT =
             new Intent(CompanionDeviceService.SERVICE_INTERFACE);
     private static final String PROPERTY_PRIMARY_TAG =
             "android.companion.PROPERTY_PRIMARY_COMPANION_DEVICE_SERVICE";
 
+    /**
+     * Get package info
+     */
     @Nullable
-    static PackageInfo getPackageInfo(@NonNull Context context,
+    public static PackageInfo getPackageInfo(@NonNull Context context,
             @UserIdInt int userId, @NonNull String packageName) {
         final PackageManager pm = context.getPackageManager();
         final PackageInfoFlags flags = PackageInfoFlags.of(GET_PERMISSIONS | GET_CONFIGURATIONS);
@@ -81,26 +82,32 @@
         });
     }
 
-    static void enforceUsesCompanionDeviceFeature(@NonNull Context context,
+    /**
+     * Require the app to declare the companion device feature.
+     */
+    public static void enforceUsesCompanionDeviceFeature(@NonNull Context context,
             @UserIdInt int userId, @NonNull String packageName) {
         // Allow system server to create CDM associations without FEATURE_COMPANION_DEVICE_SETUP
         if (getCallingUid() == Process.SYSTEM_UID) {
             return;
         }
 
-        String requiredFeature = FEATURE_COMPANION_DEVICE_SETUP;
+        PackageInfo packageInfo = getPackageInfo(context, userId, packageName);
+        if (packageInfo == null) {
+            throw new IllegalArgumentException("Package " + packageName + " doesn't exist.");
+        }
 
-        FeatureInfo[] requestedFeatures = getPackageInfo(context, userId, packageName).reqFeatures;
+        FeatureInfo[] requestedFeatures = packageInfo.reqFeatures;
         if (requestedFeatures != null) {
-            for (int i = 0; i < requestedFeatures.length; i++) {
-                if (requiredFeature.equals(requestedFeatures[i].name)) {
+            for (FeatureInfo requestedFeature : requestedFeatures) {
+                if (FEATURE_COMPANION_DEVICE_SETUP.equals(requestedFeature.name)) {
                     return;
                 }
             }
         }
 
         throw new IllegalStateException("Must declare uses-feature "
-                + requiredFeature
+                + FEATURE_COMPANION_DEVICE_SETUP
                 + " in manifest to use this API");
     }
 
@@ -109,7 +116,7 @@
      *         Services marked as "primary" would always appear at the head of the lists, *before*
      *         all non-primary services.
      */
-    static @NonNull Map<String, List<ComponentName>> getCompanionServicesForUser(
+    public static @NonNull Map<String, List<ComponentName>> getCompanionServicesForUser(
             @NonNull Context context, @UserIdInt int userId) {
         final PackageManager pm = context.getPackageManager();
         final List<ResolveInfo> companionServices = pm.queryIntentServicesAsUser(
@@ -179,9 +186,7 @@
         final String[] allowlistedPackages = context.getResources()
                 .getStringArray(com.android.internal.R.array.config_companionDevicePackages);
         if (!ArrayUtils.contains(allowlistedPackages, packageName)) {
-            if (DEBUG) {
-                Log.d(TAG, packageName + " is not allowlisted.");
-            }
+            Slog.d(TAG, packageName + " is not allowlisted.");
             return false;
         }
 
@@ -212,13 +217,6 @@
 
         if (!requestingPackageSignatureAllowlisted) {
             Slog.w(TAG, "Certificate mismatch for allowlisted package " + packageName);
-            if (DEBUG) {
-                Log.d(TAG, "  > allowlisted signatures for " + packageName + ": ["
-                        + String.join(", ", allowlistedSignatureDigestsForRequestingPackage)
-                        + "]");
-                Log.d(TAG, "  > actual signatures for " + packageName + ": "
-                        + Arrays.toString(requestingPackageSignatureDigests));
-            }
         }
 
         return requestingPackageSignatureAllowlisted;
diff --git a/services/companion/java/com/android/server/companion/PermissionsUtils.java b/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
similarity index 80%
rename from services/companion/java/com/android/server/companion/PermissionsUtils.java
rename to services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
index 15bebba..2cf1f46 100644
--- a/services/companion/java/com/android/server/companion/PermissionsUtils.java
+++ b/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.companion;
+package com.android.server.companion.utils;
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.MANAGE_COMPANION_DEVICES;
@@ -75,16 +75,22 @@
         DEVICE_PROFILE_TO_PERMISSION = unmodifiableMap(map);
     }
 
-    static void enforcePermissionsForAssociation(@NonNull Context context,
+    /**
+     * Require the app to declare necessary permission for creating association.
+     */
+    public static void enforcePermissionForCreatingAssociation(@NonNull Context context,
             @NonNull AssociationRequest request, int packageUid) {
-        enforceRequestDeviceProfilePermissions(context, request.getDeviceProfile(), packageUid);
+        enforcePermissionForRequestingProfile(context, request.getDeviceProfile(), packageUid);
 
         if (request.isSelfManaged()) {
-            enforceRequestSelfManagedPermission(context, packageUid);
+            enforcePermissionForRequestingSelfManaged(context, packageUid);
         }
     }
 
-    static void enforceRequestDeviceProfilePermissions(
+    /**
+     * Require the app to declare necessary permission for creating association with profile.
+     */
+    public static void enforcePermissionForRequestingProfile(
             @NonNull Context context, @Nullable String deviceProfile, int packageUid) {
         // Device profile can be null.
         if (deviceProfile == null) return;
@@ -101,7 +107,11 @@
         }
     }
 
-    static void enforceRequestSelfManagedPermission(@NonNull Context context, int packageUid) {
+    /**
+     * Require the app to declare necessary permission for creating self-managed association.
+     */
+    public static void enforcePermissionForRequestingSelfManaged(@NonNull Context context,
+            int packageUid) {
         if (context.checkPermission(REQUEST_COMPANION_SELF_MANAGED, getCallingPid(), packageUid)
                 != PERMISSION_GRANTED) {
             throw new SecurityException("Application does not hold "
@@ -109,25 +119,39 @@
         }
     }
 
-    static boolean checkCallerCanInteractWithUserId(@NonNull Context context, int userId) {
+    /**
+     * Check if the caller can interact with the user.
+     */
+    public static boolean checkCallerCanInteractWithUserId(@NonNull Context context, int userId) {
         if (getCallingUserId() == userId) return true;
 
         return context.checkCallingPermission(INTERACT_ACROSS_USERS) == PERMISSION_GRANTED;
     }
 
-    static void enforceCallerCanInteractWithUserId(@NonNull Context context, int userId) {
+    /**
+     * Require the caller to be able to interact with the user.
+     */
+    public static void enforceCallerCanInteractWithUserId(@NonNull Context context, int userId) {
         if (getCallingUserId() == userId) return;
 
         context.enforceCallingPermission(INTERACT_ACROSS_USERS, null);
     }
 
-    static void enforceCallerIsSystemOrCanInteractWithUserId(@NonNull Context context, int userId) {
+    /**
+     * Require the caller to be system UID or to be able to interact with the user.
+     */
+    public static void enforceCallerIsSystemOrCanInteractWithUserId(@NonNull Context context,
+            int userId) {
         if (getCallingUid() == SYSTEM_UID) return;
 
         enforceCallerCanInteractWithUserId(context, userId);
     }
 
-    static boolean checkCallerIsSystemOr(@UserIdInt int userId, @NonNull String packageName) {
+    /**
+     * Check if the caller is system UID or the provided user.
+     */
+    public static boolean checkCallerIsSystemOr(@UserIdInt int userId,
+            @NonNull String packageName) {
         final int callingUid = getCallingUid();
         if (callingUid == SYSTEM_UID) return true;
 
@@ -158,13 +182,19 @@
         }
     }
 
-    static boolean checkCallerCanManageCompanionDevice(@NonNull Context context) {
+    /**
+     * Check if the caller holds the necessary permission to manage companion devices.
+     */
+    public static boolean checkCallerCanManageCompanionDevice(@NonNull Context context) {
         if (getCallingUid() == SYSTEM_UID) return true;
 
         return context.checkCallingPermission(MANAGE_COMPANION_DEVICES) == PERMISSION_GRANTED;
     }
 
-    static void enforceCallerCanManageAssociationsForPackage(@NonNull Context context,
+    /**
+     * Require the caller to be able to manage the associations for the package.
+     */
+    public static void enforceCallerCanManageAssociationsForPackage(@NonNull Context context,
             @UserIdInt int userId, @NonNull String packageName,
             @Nullable String actionDescription) {
         if (checkCallerCanManageAssociationsForPackage(context, userId, packageName)) return;
@@ -175,7 +205,10 @@
                 + " for u" + userId + "/" + packageName);
     }
 
-    static void enforceCallerCanObservingDevicePresenceByUuid(@NonNull Context context) {
+    /**
+     * Require the caller to hold necessary permission to observe device presence by UUID.
+     */
+    public static void enforceCallerCanObservingDevicePresenceByUuid(@NonNull Context context) {
         if (context.checkCallingPermission(REQUEST_OBSERVE_DEVICE_UUID_PRESENCE)
                 != PERMISSION_GRANTED) {
             throw new SecurityException("Caller (uid=" + getCallingUid() + ") does not have "
@@ -193,7 +226,7 @@
      * </ul>
      * @return whether the caller is one of the above.
      */
-    static boolean checkCallerCanManageAssociationsForPackage(@NonNull Context context,
+    public static boolean checkCallerCanManageAssociationsForPackage(@NonNull Context context,
             @UserIdInt int userId, @NonNull String packageName) {
         if (checkCallerIsSystemOr(userId, packageName)) return true;
 
diff --git a/services/companion/java/com/android/server/companion/RolesUtils.java b/services/companion/java/com/android/server/companion/utils/RolesUtils.java
similarity index 70%
rename from services/companion/java/com/android/server/companion/RolesUtils.java
rename to services/companion/java/com/android/server/companion/utils/RolesUtils.java
index af9d2d7..f798e21 100644
--- a/services/companion/java/com/android/server/companion/RolesUtils.java
+++ b/services/companion/java/com/android/server/companion/utils/RolesUtils.java
@@ -14,13 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.server.companion;
+package com.android.server.companion.utils;
 
 import static android.app.role.RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP;
 
-import static com.android.server.companion.CompanionDeviceManagerService.DEBUG;
-import static com.android.server.companion.CompanionDeviceManagerService.TAG;
-
 import android.annotation.NonNull;
 import android.annotation.SuppressLint;
 import android.annotation.UserIdInt;
@@ -29,7 +26,6 @@
 import android.content.Context;
 import android.os.Binder;
 import android.os.UserHandle;
-import android.util.Log;
 import android.util.Slog;
 
 import java.util.List;
@@ -37,9 +33,14 @@
 
 /** Utility methods for accessing {@link RoleManager} APIs. */
 @SuppressLint("LongLogTag")
-final class RolesUtils {
+public final class RolesUtils {
 
-    static boolean isRoleHolder(@NonNull Context context, @UserIdInt int userId,
+    private static final String TAG = "CDM_RolesUtils";
+
+    /**
+     * Check if the package holds the role.
+     */
+    public static boolean isRoleHolder(@NonNull Context context, @UserIdInt int userId,
             @NonNull String packageName, @NonNull String role) {
         final RoleManager roleManager = context.getSystemService(RoleManager.class);
         final List<String> roleHolders = roleManager.getRoleHoldersAsUser(
@@ -58,13 +59,9 @@
      *                        false if failed. If the association does not have any device profile
      *                        specified, then the operation will always be successful as a no-op.
      */
-    static void addRoleHolderForAssociation(
+    public static void addRoleHolderForAssociation(
             @NonNull Context context, @NonNull AssociationInfo associationInfo,
             @NonNull Consumer<Boolean> roleGrantResult) {
-        if (DEBUG) {
-            Log.d(TAG, "addRoleHolderForAssociation() associationInfo=" + associationInfo);
-        }
-
         final String deviceProfile = associationInfo.getDeviceProfile();
         if (deviceProfile == null) {
             // If no device profile is specified, then no-op and resolve callback with success.
@@ -83,33 +80,30 @@
                 roleGrantResult);
     }
 
-    static void removeRoleHolderForAssociation(
-            @NonNull Context context, @NonNull AssociationInfo associationInfo) {
-        if (DEBUG) {
-            Log.d(TAG, "removeRoleHolderForAssociation() associationInfo=" + associationInfo);
-        }
-
-        final String deviceProfile = associationInfo.getDeviceProfile();
+    /**
+     * Remove the role for the package association.
+     */
+    public static void removeRoleHolderForAssociation(
+            @NonNull Context context, int userId, String packageName, String deviceProfile) {
         if (deviceProfile == null) return;
 
         final RoleManager roleManager = context.getSystemService(RoleManager.class);
 
-        final String packageName = associationInfo.getPackageName();
-        final int userId = associationInfo.getUserId();
         final UserHandle userHandle = UserHandle.of(userId);
 
-        Slog.i(TAG, "Removing CDM role holder, role=" + deviceProfile
-                + ", package=u" + userId + "\\" + packageName);
+        Slog.i(TAG, "Removing CDM role=" + deviceProfile
+                + " for userId=" + userId + ", packageName=" + packageName);
         final long identity = Binder.clearCallingIdentity();
         try {
             roleManager.removeRoleHolderAsUser(deviceProfile, packageName,
-                MANAGE_HOLDERS_FLAG_DONT_KILL_APP, userHandle, context.getMainExecutor(),
-                success -> {
-                    if (!success) {
-                        Slog.e(TAG, "Failed to remove u" + userId + "\\" + packageName
-                                + " from the list of " + deviceProfile + " holders.");
-                    }
-                });
+                    MANAGE_HOLDERS_FLAG_DONT_KILL_APP, userHandle, context.getMainExecutor(),
+                    success -> {
+                        if (!success) {
+                            Slog.e(TAG, "Failed to remove userId=" + userId + ", packageName="
+                                    + packageName + " from the list of " + deviceProfile
+                                    + " holders.");
+                        }
+                    });
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/services/companion/java/com/android/server/companion/Utils.java b/services/companion/java/com/android/server/companion/utils/Utils.java
similarity index 64%
rename from services/companion/java/com/android/server/companion/Utils.java
rename to services/companion/java/com/android/server/companion/utils/Utils.java
index b9f61ec..8302997 100644
--- a/services/companion/java/com/android/server/companion/Utils.java
+++ b/services/companion/java/com/android/server/companion/utils/Utils.java
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.server.companion;
+package com.android.server.companion.utils;
 
+import android.annotation.NonNull;
+import android.bluetooth.BluetoothDevice;
 import android.os.Parcel;
 import android.os.ResultReceiver;
 
@@ -43,5 +45,27 @@
         return ipcFriendly;
     }
 
+    /**
+     * Return a human-readable string for the BluetoothDevice.
+     */
+    public static String btDeviceToString(@NonNull BluetoothDevice btDevice) {
+        final StringBuilder sb = new StringBuilder(btDevice.getAddress());
+
+        sb.append(" [name=");
+        final String name = btDevice.getName();
+        if (name != null) {
+            sb.append('\'').append(name).append('\'');
+        } else {
+            sb.append("null");
+        }
+
+        final String alias = btDevice.getAlias();
+        if (alias != null) {
+            sb.append(", alias='").append(alias).append("'");
+        }
+
+        return sb.append(']').toString();
+    }
+
     private Utils() {}
 }
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index d4ff699..6b5ba96 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -50,7 +50,7 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityThread;
-import android.app.admin.DevicePolicyManagerInternal;
+import android.app.admin.DevicePolicyCache;
 import android.app.assist.ActivityId;
 import android.content.ComponentName;
 import android.content.ContentCaptureOptions;
@@ -940,7 +940,7 @@
         return new ContentProtectionConsentManager(
                 BackgroundThread.getHandler(),
                 getContext().getContentResolver(),
-                LocalServices.getService(DevicePolicyManagerInternal.class));
+                DevicePolicyCache.getInstance());
     }
 
     @Nullable
diff --git a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionConsentManager.java b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionConsentManager.java
index 488a51a..9aa5d2f 100644
--- a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionConsentManager.java
+++ b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionConsentManager.java
@@ -16,8 +16,13 @@
 
 package com.android.server.contentprotection;
 
+import static android.view.contentprotection.flags.Flags.manageDevicePolicyEnabled;
+
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.admin.DevicePolicyCache;
+import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.ContentResolver;
 import android.database.ContentObserver;
@@ -28,6 +33,7 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
 
 /**
  * Manages consent for content protection.
@@ -45,6 +51,8 @@
 
     @NonNull private final ContentResolver mContentResolver;
 
+    @NonNull private final DevicePolicyCache mDevicePolicyCache;
+
     @NonNull private final DevicePolicyManagerInternal mDevicePolicyManagerInternal;
 
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@@ -53,54 +61,98 @@
 
     private volatile boolean mCachedPackageVerifierConsent;
 
-    private volatile boolean mCachedContentProtectionConsent;
+    private volatile boolean mCachedContentProtectionUserConsent;
 
     public ContentProtectionConsentManager(
             @NonNull Handler handler,
             @NonNull ContentResolver contentResolver,
-            @NonNull DevicePolicyManagerInternal devicePolicyManagerInternal) {
+            @NonNull DevicePolicyCache devicePolicyCache) {
         mContentResolver = contentResolver;
-        mDevicePolicyManagerInternal = devicePolicyManagerInternal;
+        mDevicePolicyCache = devicePolicyCache;
+        mDevicePolicyManagerInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
         mContentObserver = new SettingsObserver(handler);
 
-        contentResolver.registerContentObserver(
-                Settings.Global.getUriFor(KEY_PACKAGE_VERIFIER_USER_CONSENT),
-                /* notifyForDescendants= */ false,
-                mContentObserver,
-                UserHandle.USER_ALL);
+        registerSettingsGlobalObserver(KEY_PACKAGE_VERIFIER_USER_CONSENT);
+        registerSettingsGlobalObserver(KEY_CONTENT_PROTECTION_USER_CONSENT);
+        readPackageVerifierConsentGranted();
+        readContentProtectionUserConsentGranted();
+    }
 
-        mCachedPackageVerifierConsent = isPackageVerifierConsentGranted();
-        mCachedContentProtectionConsent = isContentProtectionConsentGranted();
+    /** Returns true if the consent is ultimately granted. */
+    public boolean isConsentGranted(@UserIdInt int userId) {
+        return mCachedPackageVerifierConsent && isContentProtectionConsentGranted(userId);
     }
 
     /**
-     * Returns true if all the consents are granted
+     * Not always cached internally and can be expensive, when possible prefer to use {@link
+     * #mCachedPackageVerifierConsent} instead.
      */
-    public boolean isConsentGranted(@UserIdInt int userId) {
-        return mCachedPackageVerifierConsent
-                && mCachedContentProtectionConsent
-                && !isUserOrganizationManaged(userId);
-    }
-
     private boolean isPackageVerifierConsentGranted() {
-        // Not always cached internally
         return Settings.Global.getInt(
                         mContentResolver, KEY_PACKAGE_VERIFIER_USER_CONSENT, /* def= */ 0)
                 >= 1;
     }
 
-    private boolean isContentProtectionConsentGranted() {
-        // Not always cached internally
+    /**
+     * Not always cached internally and can be expensive, when possible prefer to use {@link
+     * #mCachedContentProtectionUserConsent} instead.
+     */
+    private boolean isContentProtectionUserConsentGranted() {
         return Settings.Global.getInt(
                         mContentResolver, KEY_CONTENT_PROTECTION_USER_CONSENT, /* def= */ 0)
                 >= 0;
     }
 
+    private void readPackageVerifierConsentGranted() {
+        mCachedPackageVerifierConsent = isPackageVerifierConsentGranted();
+    }
+
+    private void readContentProtectionUserConsentGranted() {
+        mCachedContentProtectionUserConsent = isContentProtectionUserConsentGranted();
+    }
+
+    /** Always cached internally, cheap and safe to use. */
     private boolean isUserOrganizationManaged(@UserIdInt int userId) {
-        // Cached internally
         return mDevicePolicyManagerInternal.isUserOrganizationManaged(userId);
     }
 
+    /** Always cached internally, cheap and safe to use. */
+    private boolean isContentProtectionPolicyGranted(@UserIdInt int userId) {
+        if (!manageDevicePolicyEnabled()) {
+            return false;
+        }
+
+        @DevicePolicyManager.ContentProtectionPolicy
+        int policy = mDevicePolicyCache.getContentProtectionPolicy(userId);
+
+        return switch (policy) {
+            case DevicePolicyManager.CONTENT_PROTECTION_ENABLED -> true;
+            case DevicePolicyManager.CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY ->
+                    mCachedContentProtectionUserConsent;
+            default -> false;
+        };
+    }
+
+    /** Always cached internally, cheap and safe to use. */
+    private boolean isContentProtectionConsentGranted(@UserIdInt int userId) {
+        if (!manageDevicePolicyEnabled()) {
+            return mCachedContentProtectionUserConsent && !isUserOrganizationManaged(userId);
+        }
+
+        return isUserOrganizationManaged(userId)
+                ? isContentProtectionPolicyGranted(userId)
+                : mCachedContentProtectionUserConsent;
+    }
+
+    private void registerSettingsGlobalObserver(@NonNull String key) {
+        registerSettingsObserver(Settings.Global.getUriFor(key));
+    }
+
+    private void registerSettingsObserver(@NonNull Uri uri) {
+        mContentResolver.registerContentObserver(
+                uri, /* notifyForDescendants= */ false, mContentObserver, UserHandle.USER_ALL);
+    }
+
     private final class SettingsObserver extends ContentObserver {
 
         SettingsObserver(Handler handler) {
@@ -108,17 +160,20 @@
         }
 
         @Override
-        public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
+        public void onChange(boolean selfChange, @Nullable Uri uri, @UserIdInt int userId) {
+            if (uri == null) {
+                return;
+            }
             final String property = uri.getLastPathSegment();
             if (property == null) {
                 return;
             }
             switch (property) {
                 case KEY_PACKAGE_VERIFIER_USER_CONSENT:
-                    mCachedPackageVerifierConsent = isPackageVerifierConsentGranted();
+                    readPackageVerifierConsentGranted();
                     return;
                 case KEY_CONTENT_PROTECTION_USER_CONSENT:
-                    mCachedContentProtectionConsent = isContentProtectionConsentGranted();
+                    readContentProtectionUserConsentGranted();
                     return;
                 default:
                     Slog.w(TAG, "Ignoring unexpected property: " + property);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 7940ca6..d1d7ee7 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -41,16 +41,18 @@
 genrule {
     name: "services.core.protologsrc",
     srcs: [
+        ":protolog-impl",
         ":protolog-groups",
         ":services.core-sources-am-wm",
     ],
     tools: ["protologtool"],
     cmd: "$(location protologtool) transform-protolog-calls " +
         "--protolog-class com.android.internal.protolog.common.ProtoLog " +
-        "--protolog-impl-class com.android.internal.protolog.ProtoLogImpl " +
-        "--protolog-cache-class 'com.android.server.wm.ProtoLogCache' " +
         "--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
         "--loggroups-jar $(location :protolog-groups) " +
+        "--viewer-config-file-path /etc/core.protolog.pb " +
+        "--legacy-viewer-config-file-path /system/etc/protolog.conf.json.gz " +
+        "--legacy-output-file-path /data/misc/wmtrace/wm_log.winscope " +
         "--output-srcjar $(out) " +
         "$(locations :services.core-sources-am-wm)",
     out: ["services.core.protolog.srcjar"],
@@ -67,12 +69,30 @@
         "--protolog-class com.android.internal.protolog.common.ProtoLog " +
         "--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
         "--loggroups-jar $(location :protolog-groups) " +
-        "--viewer-conf $(out) " +
+        "--viewer-config-type json " +
+        "--viewer-config $(out) " +
         "$(locations :services.core-sources-am-wm)",
     out: ["services.core.protolog.json"],
 }
 
 genrule {
+    name: "gen-core.protolog.pb",
+    srcs: [
+        ":protolog-groups",
+        ":services.core-sources-am-wm",
+    ],
+    tools: ["protologtool"],
+    cmd: "$(location protologtool) generate-viewer-config " +
+        "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+        "--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
+        "--loggroups-jar $(location :protolog-groups) " +
+        "--viewer-config-type proto " +
+        "--viewer-config $(out) " +
+        "$(locations :services.core-sources-am-wm)",
+    out: ["core.protolog.pb"],
+}
+
+genrule {
     name: "checked-protolog.json",
     srcs: [
         ":generate-protolog.json",
@@ -89,6 +109,22 @@
 }
 
 genrule {
+    name: "checked-core.protolog.pb",
+    srcs: [
+        ":gen-core.protolog.pb",
+        ":file-core.protolog.pb",
+    ],
+    cmd: "cp $(location :gen-core.protolog.pb) $(out) && " +
+        "{ ! (diff $(out) $(location :file-core.protolog.pb) | grep -q '^<') || " +
+        "{ echo -e '\\n\\n################################################################\\n#\\n" +
+        "#  ERROR: ProtoLog viewer config is stale.  To update it, run:\\n#\\n" +
+        "#  cp $${ANDROID_BUILD_TOP}/$(location :gen-core.protolog.pb) " +
+        "$${ANDROID_BUILD_TOP}/$(location :file-core.protolog.pb)\\n#\\n" +
+        "################################################################\\n\\n' >&2 && false; } }",
+    out: ["core.protolog.pb"],
+}
+
+genrule {
     name: "statslog-art-java-gen",
     tools: ["stats-log-api-gen"],
     cmd: "$(location stats-log-api-gen) --java $(out) --module art" +
@@ -158,6 +194,7 @@
         "default_television.xml",
         "gps_debug.conf",
         "protolog.conf.json.gz",
+        "core.protolog.pb",
     ],
 
     static_libs: [
@@ -269,3 +306,8 @@
     name: "protolog.conf.json.gz",
     src: ":services.core.json.gz",
 }
+
+prebuilt_etc {
+    name: "core.protolog.pb",
+    src: ":checked-core.protolog.pb",
+}
diff --git a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
index 0904c47..7d8aad7 100644
--- a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
+++ b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
@@ -63,6 +63,9 @@
     @Nullable private MediaProjectionManager mProjectionManager;
     @Nullable private WindowManagerInternal mWindowManager;
 
+    // screen recorder packages exempted from screen share protection.
+    private ArraySet<String> mExemptedPackages = null;
+
     final Object mSensitiveContentProtectionLock = new Object();
 
     @GuardedBy("mSensitiveContentProtectionLock")
@@ -76,7 +79,7 @@
                     Trace.beginSection(
                             "SensitiveContentProtectionManagerService.onProjectionStart");
                     try {
-                        onProjectionStart();
+                        onProjectionStart(info);
                     } finally {
                         Trace.endSection();
                     }
@@ -113,15 +116,25 @@
         if (DEBUG) Log.d(TAG, "onBootPhase - PHASE_BOOT_COMPLETED");
 
         init(getContext().getSystemService(MediaProjectionManager.class),
-                LocalServices.getService(WindowManagerInternal.class));
+                LocalServices.getService(WindowManagerInternal.class),
+                getExemptedPackages());
         if (sensitiveContentAppProtection()) {
             publishBinderService(Context.SENSITIVE_CONTENT_PROTECTION_SERVICE,
                     new SensitiveContentProtectionManagerServiceBinder());
         }
     }
 
+    // These packages are exempted from screen share protection.
+    private ArraySet<String> getExemptedPackages() {
+        final ArraySet<String> exemptedPackages =
+                SystemConfig.getInstance().getBugreportWhitelistedPackages();
+        // TODO(b/323361046) - Add sys ui recorder package.
+        return exemptedPackages;
+    }
+
     @VisibleForTesting
-    void init(MediaProjectionManager projectionManager, WindowManagerInternal windowManager) {
+    void init(MediaProjectionManager projectionManager, WindowManagerInternal windowManager,
+            ArraySet<String> exemptedPackages) {
         if (DEBUG) Log.d(TAG, "init");
 
         Objects.requireNonNull(projectionManager);
@@ -129,6 +142,7 @@
 
         mProjectionManager = projectionManager;
         mWindowManager = windowManager;
+        mExemptedPackages = exemptedPackages;
 
         // TODO(b/317250444): use MediaProjectionManagerService directly, reduces unnecessary
         //  handler, delegate, and binder death recipient
@@ -165,7 +179,11 @@
         }
     }
 
-    private void onProjectionStart() {
+    private void onProjectionStart(MediaProjectionInfo info) {
+        if (mExemptedPackages != null && mExemptedPackages.contains(info.getPackageName())) {
+            Log.w(TAG, info.getPackageName() + " is exempted from screen share protection.");
+            return;
+        }
         // TODO(b/324447419): move GlobalSettings lookup to background thread
         boolean disableScreenShareProtections =
                 Settings.Global.getInt(getContext().getContentResolver(),
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index 9189ea7..e1d7be1 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -348,6 +348,9 @@
     // marked as stopped by the system
     @NonNull private final Set<String> mInitialNonStoppedSystemPackages = new ArraySet<>();
 
+    // Which packages (key) are allowed to join particular SharedUid (value).
+    @NonNull private final Map<String, String> mPackageToSharedUidAllowList = new ArrayMap<>();
+
     // A map of preloaded package names and the path to its app metadata file path.
     private final ArrayMap<String, String> mAppMetadataFilePaths = new ArrayMap<>();
 
@@ -567,6 +570,11 @@
         return mInitialNonStoppedSystemPackages;
     }
 
+    @NonNull
+    public Map<String, String> getPackageToSharedUidAllowList() {
+        return mPackageToSharedUidAllowList;
+    }
+
     public ArrayMap<String, String> getAppMetadataFilePaths() {
         return mAppMetadataFilePaths;
     }
@@ -1563,6 +1571,19 @@
                             mInitialNonStoppedSystemPackages.add(pkgName);
                         }
                     } break;
+                    case "allow-package-shareduid": {
+                        String pkgName = parser.getAttributeValue(null, "package");
+                        String sharedUid = parser.getAttributeValue(null, "shareduid");
+                        if (TextUtils.isEmpty(pkgName)) {
+                            Slog.w(TAG, "<" + name + "> without package in " + permFile
+                                    + " at " + parser.getPositionDescription());
+                        } else if (TextUtils.isEmpty(sharedUid)) {
+                            Slog.w(TAG, "<" + name + "> without shareduid in " + permFile
+                                    + " at " + parser.getPositionDescription());
+                        } else {
+                            mPackageToSharedUidAllowList.put(pkgName, sharedUid);
+                        }
+                    }
                     case "asl-file": {
                         String packageName = parser.getAttributeValue(null, "package");
                         String path = parser.getAttributeValue(null, "path");
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index 7dc9f10..4de85fe 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -39,7 +39,9 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * The base class for services running in the system process. Override and implement
@@ -135,6 +137,7 @@
     public @interface BootPhase {}
 
     private final Context mContext;
+    private final List<Class<?>> mDependencies;
 
     /**
      * Class representing user in question in the lifecycle callbacks.
@@ -332,7 +335,28 @@
      * @param context The system server context.
      */
     public SystemService(@NonNull Context context) {
+        this(context, Collections.emptyList());
+    }
+
+    /**
+     * Initializes the system service.
+     * <p>
+     * Subclasses must define a single argument constructor that accepts the context
+     * and passes it to super.
+     * </p>
+     *
+     * @param context The system server context.
+     * @param dependencies The list of dependencies that this service requires to operate.
+     *                     Currently only used by the Ravenwood deviceless testing environment to
+     *                     understand transitive dependencies needed to support a specific test.
+     *                     For example, including {@code PowerManager.class} here indicates that
+     *                     this service requires the {@code PowerManager} and/or {@code
+     *                     PowerManagerInternal} APIs to function.
+     * @hide
+     */
+    public SystemService(@NonNull Context context, @NonNull List<Class<?>> dependencies) {
         mContext = context;
+        mDependencies = Objects.requireNonNull(dependencies);
     }
 
     /**
@@ -356,6 +380,22 @@
     }
 
     /**
+     * Get the list of dependencies that this service requires to operate.
+     *
+     * Currently only used by the Ravenwood deviceless testing environment to understand transitive
+     * dependencies needed to support a specific test.
+     *
+     * For example, including {@code PowerManager.class} here indicates that this service
+     * requires the {@code PowerManager} and/or {@code PowerManagerInternal} APIs to function.
+     *
+     * @hide
+     */
+    @NonNull
+    public final List<Class<?>> getDependencies() {
+        return mDependencies;
+    }
+
+    /**
      * Returns true if the system is running in safe mode.
      * TODO: we should define in which phase this becomes valid
      *
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 5e9d1cb..8dc15ad 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -163,6 +163,9 @@
                 }
             ],
             "file_patterns": ["PinnerService\\.java"]
+        },
+        {
+            "name": "FrameworksVpnTests"
         }
     ]
 }
diff --git a/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java b/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java
index 3312be2..0e0bf81 100644
--- a/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java
+++ b/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java
@@ -20,6 +20,7 @@
 
 import android.app.KeyguardManager;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.hardware.biometrics.AuthenticationStateListener;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricSourceType;
@@ -32,8 +33,10 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseIntArray;
+import android.util.SparseLongArray;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockSettingsInternal;
 import com.android.internal.widget.LockSettingsStateListener;
@@ -57,6 +60,8 @@
     private static final int MSG_REPORT_BIOMETRIC_AUTH_ATTEMPT = 2;
     private static final int AUTH_SUCCESS = 1;
     private static final int AUTH_FAILURE = 0;
+    private static final int TYPE_PRIMARY_AUTH = 0;
+    private static final int TYPE_BIOMETRIC_AUTH = 1;
 
     private final LockPatternUtils mLockPatternUtils;
     private final LockSettingsInternal mLockSettings;
@@ -67,6 +72,7 @@
     private final UserManagerInternal mUserManager;
     @VisibleForTesting
     final SparseIntArray mFailedAttemptsForUser = new SparseIntArray();
+    private final SparseLongArray mLastLockedTimestamp = new SparseLongArray();
 
     public AdaptiveAuthService(Context context) {
         this(context, new LockPatternUtils(context));
@@ -170,7 +176,7 @@
             Slog.d(TAG, "handleReportPrimaryAuthAttempt: success=" + success
                     + ", userId=" + userId);
         }
-        reportAuthAttempt(success, userId);
+        reportAuthAttempt(TYPE_PRIMARY_AUTH, success, userId);
     }
 
     private void handleReportBiometricAuthAttempt(boolean success, int userId) {
@@ -178,13 +184,29 @@
             Slog.d(TAG, "handleReportBiometricAuthAttempt: success=" + success
                     + ", userId=" + userId);
         }
-        reportAuthAttempt(success, userId);
+        reportAuthAttempt(TYPE_BIOMETRIC_AUTH, success, userId);
     }
 
-    private void reportAuthAttempt(boolean success, int userId) {
+    private void reportAuthAttempt(int authType, boolean success, int userId) {
+        // Disable adaptive auth for automotive devices by default
+        if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+            return;
+        }
+
         if (success) {
             // Deleting the entry effectively resets the counter of failed attempts for the user
             mFailedAttemptsForUser.delete(userId);
+
+            // Collect metrics if the device was locked by adaptive auth before
+            if (mLastLockedTimestamp.indexOfKey(userId) >= 0) {
+                final long lastLockedTime = mLastLockedTimestamp.get(userId);
+                collectTimeElapsedSinceLastLocked(
+                        lastLockedTime, SystemClock.elapsedRealtime(), authType);
+
+                // Remove the entry for the last locked time because a successful auth just happened
+                // and metrics have been collected
+                mLastLockedTimestamp.delete(userId);
+            }
             return;
         }
 
@@ -210,6 +232,34 @@
         lockDevice(userId);
     }
 
+    private static void collectTimeElapsedSinceLastLocked(long lastLockedTime, long authTime,
+            int authType) {
+        final int unlockType =  switch (authType) {
+            case TYPE_PRIMARY_AUTH -> FrameworkStatsLog
+                    .ADAPTIVE_AUTH_UNLOCK_AFTER_LOCK_REPORTED__UNLOCK_TYPE__PRIMARY_AUTH;
+            case TYPE_BIOMETRIC_AUTH -> FrameworkStatsLog
+                    .ADAPTIVE_AUTH_UNLOCK_AFTER_LOCK_REPORTED__UNLOCK_TYPE__BIOMETRIC_AUTH;
+            default -> FrameworkStatsLog
+                    .ADAPTIVE_AUTH_UNLOCK_AFTER_LOCK_REPORTED__UNLOCK_TYPE__UNKNOWN;
+        };
+
+        if (DEBUG) {
+            Slog.d(TAG, "collectTimeElapsedSinceLastLockedForUser: "
+                    + "lastLockedTime=" + lastLockedTime
+                    + ", authTime=" + authTime
+                    + ", unlockType=" + unlockType);
+        }
+
+        // This usually shouldn't happen, and just check out of an abundance of caution
+        if (lastLockedTime > authTime) {
+            return;
+        }
+
+        // Log to statsd
+        FrameworkStatsLog.write(FrameworkStatsLog.ADAPTIVE_AUTH_UNLOCK_AFTER_LOCK_REPORTED,
+                lastLockedTime, authTime, unlockType);
+    }
+
     /**
      * Locks the device and requires primary auth or biometric auth for unlocking
      */
@@ -234,5 +284,9 @@
 
         // Lock the device
         mWindowManager.lockNow();
+
+        // Record the time that the device is locked by adaptive auth to collect metrics when the
+        // next successful primary or biometric auth happens
+        mLastLockedTimestamp.put(userId, SystemClock.elapsedRealtime());
     }
 }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index b8f6b3f..258f53d 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -372,6 +372,15 @@
     @Overridable
     public static final long FGS_BOOT_COMPLETED_RESTRICTIONS = 296558535L;
 
+    /**
+     * Disables foreground service background starts in System Alert Window for all types
+     * unless it already has a System Overlay Window.
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = VERSION_CODES.VANILLA_ICE_CREAM)
+    @Overridable
+    public static final long FGS_SAW_RESTRICTIONS = 319471980L;
+
     final ActivityManagerService mAm;
 
     // Maximum number of services that we allow to start in the background
@@ -4133,7 +4142,7 @@
                         || (callerApp.mState.getCurProcState() <= PROCESS_STATE_TOP
                             && c.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)),
                         b.client);
-                if ((serviceBindingOomAdjPolicy
+                if (!s.mOomAdjBumpedInExec && (serviceBindingOomAdjPolicy
                         & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CONNECT) == 0) {
                     needOomAdj = true;
                     mAm.enqueueOomAdjTargetLocked(s.app);
@@ -4277,7 +4286,7 @@
                 }
 
                 serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false, false,
-                        !Flags.serviceBindingOomAdjPolicy() || b == null || !b.mSkippedOomAdj
+                        !Flags.serviceBindingOomAdjPolicy() || r.mOomAdjBumpedInExec
                         ? OOM_ADJ_REASON_EXECUTING_SERVICE : OOM_ADJ_REASON_NONE);
             }
         } finally {
@@ -4398,7 +4407,6 @@
                         + (b != null ? b.apps.size() : 0));
 
                 boolean inDestroying = mDestroyingServices.contains(r);
-                boolean skipOomAdj = false;
                 if (b != null) {
                     if (b.apps.size() > 0 && !inDestroying) {
                         // Applications have already bound since the last
@@ -4423,11 +4431,11 @@
                         // a new client.
                         b.doRebind = true;
                     }
-                    skipOomAdj = Flags.serviceBindingOomAdjPolicy() && b.mSkippedOomAdj;
                 }
 
                 serviceDoneExecutingLocked(r, inDestroying, false, false,
-                        skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE);
+                        !Flags.serviceBindingOomAdjPolicy() || r.mOomAdjBumpedInExec
+                        ? OOM_ADJ_REASON_UNBIND_SERVICE : OOM_ADJ_REASON_NONE);
             }
         } finally {
             mAm.mInjector.restoreCallingIdentity(origId);
@@ -4905,9 +4913,8 @@
      * Bump the given service record into executing state.
      * @param oomAdjReason The caller requests it to perform the oomAdjUpdate not {@link
      *         ActivityManagerInternal#OOM_ADJ_REASON_NONE}.
-     * @return {@code true} if it performed oomAdjUpdate.
      */
-    private boolean bumpServiceExecutingLocked(
+    private void bumpServiceExecutingLocked(
             ServiceRecord r, boolean fg, String why, @OomAdjReason int oomAdjReason,
             boolean skipTimeoutIfPossible) {
         if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, ">>> EXECUTING "
@@ -4972,19 +4979,17 @@
                 }
             }
         }
-        boolean oomAdjusted = false;
         if (oomAdjReason != OOM_ADJ_REASON_NONE && r.app != null
                 && r.app.mState.getCurProcState() > ActivityManager.PROCESS_STATE_SERVICE) {
             // Force an immediate oomAdjUpdate, so the client app could be in the correct process
             // state before doing any service related transactions
             mAm.enqueueOomAdjTargetLocked(r.app);
             mAm.updateOomAdjPendingTargetsLocked(oomAdjReason);
-            oomAdjusted = true;
+            r.mOomAdjBumpedInExec = true;
         }
         r.executeFg |= fg;
         r.executeNesting++;
         r.executingStart = SystemClock.uptimeMillis();
-        return oomAdjusted;
     }
 
     private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
@@ -5001,7 +5006,7 @@
                 & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_BIND) != 0;
         if ((!i.requested || rebind) && i.apps.size() > 0) {
             try {
-                i.mSkippedOomAdj = !bumpServiceExecutingLocked(r, execInFg, "bind",
+                bumpServiceExecutingLocked(r, execInFg, "bind",
                         skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_BIND_SERVICE,
                         skipOomAdj /* skipTimeoutIfPossible */);
                 if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
@@ -5020,14 +5025,16 @@
                 if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e);
                 final boolean inDestroying = mDestroyingServices.contains(r);
                 serviceDoneExecutingLocked(r, inDestroying, inDestroying, false,
-                        skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE);
+                        !Flags.serviceBindingOomAdjPolicy() || r.mOomAdjBumpedInExec
+                        ? OOM_ADJ_REASON_UNBIND_SERVICE : OOM_ADJ_REASON_NONE);
                 throw e;
             } catch (RemoteException e) {
                 if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
                 // Keep the executeNesting count accurate.
                 final boolean inDestroying = mDestroyingServices.contains(r);
                 serviceDoneExecutingLocked(r, inDestroying, inDestroying, false,
-                        skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE);
+                        !Flags.serviceBindingOomAdjPolicy() || r.mOomAdjBumpedInExec
+                        ? OOM_ADJ_REASON_UNBIND_SERVICE : OOM_ADJ_REASON_NONE);
                 return false;
             }
         }
@@ -5823,6 +5830,7 @@
             // process state before doing any service related transactions
             mAm.enqueueOomAdjTargetLocked(app);
             mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_SERVICE);
+            r.mOomAdjBumpedInExec = true;
         } else {
             // Since we skipped the oom adj update, the Service#onCreate() might be running in
             // the cached state, if the service process drops into the cached state after the call.
@@ -5863,7 +5871,8 @@
                 // Keep the executeNesting count accurate.
                 final boolean inDestroying = mDestroyingServices.contains(r);
                 serviceDoneExecutingLocked(r, inDestroying, inDestroying, false,
-                        skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_STOP_SERVICE);
+                        !Flags.serviceBindingOomAdjPolicy() || r.mOomAdjBumpedInExec
+                        ? OOM_ADJ_REASON_STOP_SERVICE : OOM_ADJ_REASON_NONE);
 
                 // Cleanup.
                 if (newService) {
@@ -5898,7 +5907,7 @@
                     null, null, 0, null, null, ActivityManager.PROCESS_STATE_UNKNOWN));
         }
 
-        sendServiceArgsLocked(r, execInFg, true);
+        sendServiceArgsLocked(r, execInFg, r.mOomAdjBumpedInExec);
 
         if (r.delayed) {
             if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
@@ -6085,7 +6094,8 @@
             }
         }
 
-        boolean oomAdjusted = false;
+        boolean oomAdjusted = Flags.serviceBindingOomAdjPolicy() && r.mOomAdjBumpedInExec;
+
         // Tell the service that it has been unbound.
         if (r.app != null && r.app.isThreadReady()) {
             for (int i = r.bindings.size() - 1; i >= 0; i--) {
@@ -6094,9 +6104,10 @@
                         + ": hasBound=" + ibr.hasBound);
                 if (ibr.hasBound) {
                     try {
-                        oomAdjusted |= bumpServiceExecutingLocked(r, false, "bring down unbind",
-                                OOM_ADJ_REASON_UNBIND_SERVICE,
-                                false /* skipTimeoutIfPossible */);
+                        bumpServiceExecutingLocked(r, false, "bring down unbind",
+                                oomAdjusted ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE,
+                                oomAdjusted /* skipTimeoutIfPossible */);
+                        oomAdjusted |= r.mOomAdjBumpedInExec;
                         ibr.hasBound = false;
                         ibr.requested = false;
                         r.app.getThread().scheduleUnbindService(r,
@@ -6252,10 +6263,11 @@
                     }
                 } else {
                     try {
-                        oomAdjusted |= bumpServiceExecutingLocked(r, false, "destroy",
-                                oomAdjusted ? 0 : OOM_ADJ_REASON_STOP_SERVICE,
-                                false /* skipTimeoutIfPossible */);
+                        bumpServiceExecutingLocked(r, false, "destroy",
+                                oomAdjusted ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE,
+                                oomAdjusted /* skipTimeoutIfPossible */);
                         mDestroyingServices.add(r);
+                        oomAdjusted |= r.mOomAdjBumpedInExec;
                         r.destroying = true;
                         r.app.getThread().scheduleStopService(r);
                     } catch (Exception e) {
@@ -6411,7 +6423,7 @@
                 final boolean skipOomAdj = (serviceBindingOomAdjPolicy
                         & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CONNECT) != 0;
                 try {
-                    b.intent.mSkippedOomAdj = !bumpServiceExecutingLocked(s, false, "unbind",
+                    bumpServiceExecutingLocked(s, false, "unbind",
                             skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE,
                             skipOomAdj /* skipTimeoutIfPossible */);
                     if (b.client != s.app && c.notHasFlag(Context.BIND_WAIVE_PRIORITY)
@@ -6461,6 +6473,7 @@
         boolean inDestroying = mDestroyingServices.contains(r);
         if (r != null) {
             boolean skipOomAdj = false;
+            boolean needOomAdj = false;
             if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
                 // This is a call from a service start...  take care of
                 // book-keeping.
@@ -6536,15 +6549,13 @@
                     // Fake it to keep from ANR due to orphaned entry.
                     r.executeNesting = 1;
                 }
-            } else if (type == ActivityThread.SERVICE_DONE_EXECUTING_REBIND
-                    || type == ActivityThread.SERVICE_DONE_EXECUTING_UNBIND) {
-                final Intent.FilterComparison filter = new Intent.FilterComparison(intent);
-                final IntentBindRecord b = r.bindings.get(filter);
-                skipOomAdj = Flags.serviceBindingOomAdjPolicy() && b != null && b.mSkippedOomAdj;
+                // The service is done, force an oom adj update.
+                needOomAdj = true;
             }
             final long origId = mAm.mInjector.clearCallingIdentity();
             serviceDoneExecutingLocked(r, inDestroying, inDestroying, enqueueOomAdj,
-                    skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_EXECUTING_SERVICE);
+                    !Flags.serviceBindingOomAdjPolicy() || r.mOomAdjBumpedInExec || needOomAdj
+                    ? OOM_ADJ_REASON_EXECUTING_SERVICE : OOM_ADJ_REASON_NONE);
             mAm.mInjector.restoreCallingIdentity(origId);
         } else {
             Slog.w(TAG, "Done executing unknown service from pid "
@@ -6600,18 +6611,16 @@
                     mDestroyingServices.remove(r);
                     r.bindings.clear();
                 }
-                boolean oomAdjusted = false;
                 if (oomAdjReason != OOM_ADJ_REASON_NONE) {
                     if (enqueueOomAdj) {
                         mAm.enqueueOomAdjTargetLocked(r.app);
                     } else {
                         mAm.updateOomAdjLocked(r.app, oomAdjReason);
                     }
-                    oomAdjusted = true;
                 } else {
                     // Skip oom adj if it wasn't bumped during the bumpServiceExecutingLocked()
-                    oomAdjusted = false;
                 }
+                r.mOomAdjBumpedInExec = false;
             }
             r.executeFg = false;
             if (r.tracker != null) {
@@ -6995,6 +7004,7 @@
             sr.setProcess(null, null, 0, null);
             sr.isolationHostProc = null;
             sr.executeNesting = 0;
+            sr.mOomAdjBumpedInExec = false;
             synchronized (mAm.mProcessStats.mLock) {
                 sr.forceClearTracker();
             }
@@ -8525,10 +8535,31 @@
             }
         }
 
+        // The flag being enabled isn't enough to deny background start: we need to also check
+        // if there is a system alert UI present.
         if (ret == REASON_DENIED) {
-            if (mAm.mAtmInternal.hasSystemAlertWindowPermission(callingUid, callingPid,
-                    callingPackage)) {
-                ret = REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
+            // Flag check: are we disabling SAW FGS background starts?
+            final boolean shouldDisableSaw = Flags.fgsDisableSaw()
+                    && CompatChanges.isChangeEnabled(FGS_BOOT_COMPLETED_RESTRICTIONS, callingUid);
+            if (shouldDisableSaw) {
+                final ProcessRecord processRecord = mAm
+                        .getProcessRecordLocked(targetService.processName,
+                                targetService.appInfo.uid);
+                if (processRecord != null) {
+                    if (processRecord.mState.hasOverlayUi()) {
+                        if (mAm.mAtmInternal.hasSystemAlertWindowPermission(callingUid, callingPid,
+                                callingPackage)) {
+                            ret = REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
+                        }
+                    }
+                } else {
+                    Slog.e(TAG, "Could not find process record for SAW check");
+                }
+            } else {
+                if (mAm.mAtmInternal.hasSystemAlertWindowPermission(callingUid, callingPid,
+                        callingPackage)) {
+                    ret = REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2dd2f8f..663ba8a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9028,6 +9028,7 @@
                         Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid "
                                 + Process.myUid());
                         BinderProxy.dumpProxyDebugInfo();
+                        CriticalEventLog.getInstance().logExcessiveBinderCalls(uid);
                         if (uid == Process.SYSTEM_UID) {
                             Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
                         } else {
@@ -18462,7 +18463,8 @@
                             (WindowProcessController) procsToKill.get(i);
                     final ProcessRecord pr = (ProcessRecord) wpc.mOwner;
                     if (ActivityManager.isProcStateBackground(pr.mState.getSetProcState())
-                            && pr.mReceivers.numberOfCurReceivers() == 0) {
+                            && pr.mReceivers.numberOfCurReceivers() == 0
+                            && !pr.mState.hasStartedServices()) {
                         pr.killLocked("remove task", ApplicationExitInfo.REASON_USER_REQUESTED,
                                 ApplicationExitInfo.SUBREASON_REMOVE_TASK, true);
                     } else {
diff --git a/services/core/java/com/android/server/am/IntentBindRecord.java b/services/core/java/com/android/server/am/IntentBindRecord.java
index db47e3f..1a3652e 100644
--- a/services/core/java/com/android/server/am/IntentBindRecord.java
+++ b/services/core/java/com/android/server/am/IntentBindRecord.java
@@ -49,14 +49,6 @@
 
     String stringName;      // caching of toString
 
-    /**
-     * Mark if we've skipped oom adj update before calling into the {@link Service#onBind()}
-     * or {@link Service#onUnbind()}.
-     *
-     * <p>If it's true, we'll skip the oom adj update too during the serviceDoneExecuting.
-     */
-    boolean mSkippedOomAdj;
-
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("service="); pw.println(service);
         dumpInService(pw, prefix);
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 9568116..31328ae 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -3322,7 +3322,8 @@
                 reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
             }
             if (app.getWaitingToKill() != null && app.mReceivers.numberOfCurReceivers() == 0
-                    && ActivityManager.isProcStateBackground(state.getSetProcState())) {
+                    && ActivityManager.isProcStateBackground(state.getSetProcState())
+                    && !state.hasStartedServices()) {
                 app.killLocked(app.getWaitingToKill(), ApplicationExitInfo.REASON_USER_REQUESTED,
                         ApplicationExitInfo.SUBREASON_REMOVE_TASK, true);
                 success = false;
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 1412259..2ef433c 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -64,6 +64,9 @@
 import java.io.File;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.UUID;
 import java.util.concurrent.ExecutionException;
@@ -76,6 +79,9 @@
  * The error state of the process, such as if it's crashing/ANR etc.
  */
 class ProcessErrorStateRecord {
+    private static final DateTimeFormatter DROPBOX_TIME_FORMATTER =
+            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSZ");
+
     final ProcessRecord mApp;
     private final ActivityManagerService mService;
 
@@ -444,6 +450,13 @@
             info.append("ErrorId: ").append(errorId.toString()).append("\n");
         }
         info.append("Frozen: ").append(mApp.mOptRecord.isFrozen()).append("\n");
+        if (timeoutRecord != null && timeoutRecord.mEndUptimeMillis > 0) {
+            long millisSinceEndUptimeMs = anrTime - timeoutRecord.mEndUptimeMillis;
+            String formattedTime = DROPBOX_TIME_FORMATTER.format(
+                    Instant.now().minusMillis(millisSinceEndUptimeMs)
+                            .atZone(ZoneId.systemDefault()));
+            info.append("Timestamp: ").append(formattedTime).append("\n");
+        }
 
         // Retrieve controller with max ANR delay from AnrControllers
         // Note that we retrieve the controller before dumping stacks because dumping stacks can
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 3c8d7fc..e3aac02 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -267,6 +267,11 @@
     int mAllowStart_byBindings = REASON_DENIED;
 
     /**
+     * Whether or not we've bumped its oom adj scores during its execution.
+     */
+    boolean mOomAdjBumpedInExec;
+
+    /**
      * Whether to use the new "while-in-use permission" logic for FGS start
      */
     private boolean useNewWiuLogic_forStart() {
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 966fe5b..d1bda79 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -126,6 +126,7 @@
         "arc_next",
         "avic",
         "bluetooth",
+        "brownout_mitigation_audio",
         "build",
         "biometrics",
         "biometrics_framework",
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 34ba7f0..3abfe082 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1468,7 +1468,7 @@
 
         // Send PROFILE_INACCESSIBLE broadcast if a profile was stopped
         final UserInfo userInfo = getUserInfo(userId);
-        if (userInfo.isProfile()) {
+        if (userInfo != null && userInfo.isProfile()) {
             UserInfo parent = mInjector.getUserManager().getProfileParent(userId);
             if (parent != null) {
                 broadcastProfileAccessibleStateChanged(userId, parent.id,
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 16dbe18..b1823b4 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -23,6 +23,13 @@
 }
 
 flag {
+    name: "fgs_disable_saw"
+    namespace: "backstage_power"
+    description: "Disable System Alert Window FGS start"
+    bug: "296558535"
+}
+
+flag {
     name: "bfgs_managed_network_access"
     namespace: "backstage_power"
     description: "Restrict network access for certain applications in BFGS process state"
@@ -53,3 +60,10 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    namespace: "backstage_power"
+    name: "defer_outgoing_bcasts"
+    description: "Defer outgoing broadcasts from processes in freezable state"
+    bug: "327496592"
+}
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
index 5f12ce1..9f31f37 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
@@ -73,8 +73,7 @@
     private static final Set<Integer> DEFAULT_EVENT_SET = Sets.newHashSet(
             AmbientContextEvent.EVENT_COUGH,
             AmbientContextEvent.EVENT_SNORE,
-            AmbientContextEvent.EVENT_BACK_DOUBLE_TAP,
-            AmbientContextEvent.EVENT_HEART_RATE);
+            AmbientContextEvent.EVENT_BACK_DOUBLE_TAP);
 
     /** Default value in absence of {@link DeviceConfig} override. */
     private static final boolean DEFAULT_SERVICE_ENABLED = true;
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 0cc6494..fb62785 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -661,8 +661,12 @@
         @NonNull OpEntry createEntryLocked(String persistentDeviceId) {
             // TODO(b/308201969): Update this method when we introduce disk persistence of events
             // for accesses on external devices.
-            final ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get(
+            ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get(
                     persistentDeviceId);
+            if (attributedOps == null) {
+                attributedOps = new ArrayMap<>();
+            }
+
             final ArrayMap<String, AppOpsManager.AttributedOpEntry> attributionEntries =
                     new ArrayMap<>(attributedOps.size());
             for (int i = 0; i < attributedOps.size(); i++) {
@@ -680,8 +684,12 @@
         @NonNull OpEntry createSingleAttributionEntryLocked(@Nullable String attributionTag) {
             // TODO(b/308201969): Update this method when we introduce disk persistence of events
             // for accesses on external devices.
-            final ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get(
+            ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get(
                     PERSISTENT_DEVICE_ID_DEFAULT);
+            if (attributedOps == null) {
+                attributedOps = new ArrayMap<>();
+            }
+
             final ArrayMap<String, AttributedOpEntry> attributionEntries = new ArrayMap<>(1);
             if (attributedOps.get(attributionTag) != null) {
                 attributionEntries.put(attributionTag,
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index cb6d26f..d4f04b5 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3713,7 +3713,7 @@
                     && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
                     && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
                 if (DEBUG_VOL) {
-                    Log.d(TAG, "adjustSreamVolume: postSetAvrcpAbsoluteVolumeIndex index="
+                    Log.d(TAG, "adjustStreamVolume: postSetAvrcpAbsoluteVolumeIndex index="
                             + newIndex + "stream=" + streamType);
                 }
                 mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(newIndex / 10);
@@ -3727,7 +3727,7 @@
                     && streamType == getBluetoothContextualVolumeStream()
                     && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
                 if (DEBUG_VOL) {
-                    Log.d(TAG, "adjustSreamVolume postSetLeAudioVolumeIndex index="
+                    Log.d(TAG, "adjustStreamVolume postSetLeAudioVolumeIndex index="
                             + newIndex + " stream=" + streamType);
                 }
                 mDeviceBroker.postSetLeAudioVolumeIndex(newIndex,
@@ -3740,7 +3740,7 @@
                 // the one expected by the hearing aid
                 if (streamType == getBluetoothContextualVolumeStream()) {
                     if (DEBUG_VOL) {
-                        Log.d(TAG, "adjustSreamVolume postSetHearingAidVolumeIndex index="
+                        Log.d(TAG, "adjustStreamVolume postSetHearingAidVolumeIndex index="
                                 + newIndex + " stream=" + streamType);
                     }
                     mDeviceBroker.postSetHearingAidVolumeIndex(newIndex, streamType);
@@ -4722,7 +4722,7 @@
                 && streamType == getBluetoothContextualVolumeStream()
                 && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
             if (DEBUG_VOL) {
-                Log.d(TAG, "adjustSreamVolume postSetLeAudioVolumeIndex index="
+                Log.d(TAG, "setStreamVolume postSetLeAudioVolumeIndex index="
                         + index + " stream=" + streamType);
             }
             mDeviceBroker.postSetLeAudioVolumeIndex(index, mStreamStates[streamType].getMaxIndex(),
@@ -12528,6 +12528,16 @@
             if (app == null) {
                 return AudioManager.ERROR;
             }
+            if (android.media.audiopolicy.Flags.audioMixOwnership()) {
+                for (AudioMix mix : policyConfig.getMixes()) {
+                    if (!app.getMixes().contains(mix)) {
+                        Slog.e(TAG,
+                                "removeMixForPolicy attempted to unregister AudioMix(es) not "
+                                        + "belonging to the AudioPolicy");
+                        return AudioManager.ERROR;
+                    }
+                }
+            }
             return app.removeMixes(policyConfig.getMixes()) == AudioSystem.SUCCESS
                 ? AudioManager.SUCCESS : AudioManager.ERROR;
         }
@@ -13306,7 +13316,13 @@
             }
             final long identity = Binder.clearCallingIdentity();
             try {
-                mAudioSystem.registerPolicyMixes(mMixes, false);
+                if (android.media.audiopolicy.Flags.audioMixOwnership()) {
+                    synchronized (mMixes) {
+                        removeMixes(new ArrayList(mMixes));
+                    }
+                } else {
+                    mAudioSystem.registerPolicyMixes(mMixes, false);
+                }
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -13350,6 +13366,17 @@
 
         int addMixes(@NonNull ArrayList<AudioMix> mixes) {
             synchronized (mMixes) {
+                if (android.media.audiopolicy.Flags.audioMixOwnership()) {
+                    for (AudioMix mix : mixes) {
+                        setMixRegistration(mix);
+                    }
+
+                    int result = mAudioSystem.registerPolicyMixes(mixes, true);
+                    if (result == AudioSystem.SUCCESS) {
+                        this.add(mixes);
+                    }
+                    return result;
+                }
                 this.add(mixes);
                 return mAudioSystem.registerPolicyMixes(mixes, true);
             }
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 007b746..fb826c8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -24,6 +24,7 @@
 import android.app.TaskStackListener;
 import android.content.Context;
 import android.content.pm.UserInfo;
+import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricFaceConstants;
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.hardware.biometrics.ComponentInfoInternal;
@@ -39,6 +40,7 @@
 import android.hardware.face.FaceSensorPropertiesInternal;
 import android.hardware.face.IFaceServiceReceiver;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -64,6 +66,7 @@
 import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.BiometricScheduler;
 import com.android.server.biometrics.sensors.BiometricStateCallback;
+import com.android.server.biometrics.sensors.BiometricUtils;
 import com.android.server.biometrics.sensors.ClientMonitorCallback;
 import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
 import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
@@ -359,6 +362,17 @@
                     null /* callback */);
         }
 
+        if (Build.isDebuggable()) {
+            BiometricUtils<Face> utils = FaceUtils.getInstance(
+                    mFaceSensors.keyAt(0));
+            for (UserInfo user : UserManager.get(mContext).getAliveUsers()) {
+                List<Face> enrollments = utils.getBiometricsForUser(mContext, user.id);
+                Slog.d(getTag(), "Expecting enrollments for user " + user.id + ": "
+                        + enrollments.stream().map(
+                        BiometricAuthenticator.Identifier::getBiometricId).toList());
+            }
+        }
+
         return mDaemon;
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index a104cf4..c04c47e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.content.pm.UserInfo;
 import android.content.res.TypedArray;
+import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.IInvalidationCallback;
@@ -46,6 +47,7 @@
 import android.hardware.fingerprint.ISidefpsController;
 import android.hardware.fingerprint.IUdfpsOverlayController;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -71,6 +73,7 @@
 import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.BiometricScheduler;
 import com.android.server.biometrics.sensors.BiometricStateCallback;
+import com.android.server.biometrics.sensors.BiometricUtils;
 import com.android.server.biometrics.sensors.ClientMonitorCallback;
 import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
 import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
@@ -382,6 +385,17 @@
                     null /* callback */);
         }
 
+        if (Build.isDebuggable()) {
+            BiometricUtils<Fingerprint> utils = FingerprintUtils.getInstance(
+                    mFingerprintSensors.keyAt(0));
+            for (UserInfo user : UserManager.get(mContext).getAliveUsers()) {
+                List<Fingerprint> enrollments = utils.getBiometricsForUser(mContext, user.id);
+                Slog.d(getTag(), "Expecting enrollments for user " + user.id + ": "
+                        + enrollments.stream().map(
+                                BiometricAuthenticator.Identifier::getBiometricId).toList());
+            }
+        }
+
         return mDaemon;
     }
 
diff --git a/services/core/java/com/android/server/connectivity/TEST_MAPPING b/services/core/java/com/android/server/connectivity/TEST_MAPPING
index 687d4b0..f508319 100644
--- a/services/core/java/com/android/server/connectivity/TEST_MAPPING
+++ b/services/core/java/com/android/server/connectivity/TEST_MAPPING
@@ -7,7 +7,7 @@
                   "exclude-annotation": "com.android.testutils.SkipPresubmit"
               }
           ],
-          "file_patterns": ["Vpn\\.java", "VpnIkeV2Utils\\.java", "VpnProfileStore\\.java"]
+          "file_patterns": ["VpnIkeV2Utils\\.java", "VpnProfileStore\\.java"]
       }
   ],
   "presubmit-large": [
@@ -26,5 +26,10 @@
           ],
         "file_patterns": ["Vpn\\.java", "VpnIkeV2Utils\\.java", "VpnProfileStore\\.java"]
       }
+  ],
+  "postsubmit":[
+    {
+      "name":"FrameworksVpnTests"
+    }
   ]
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/criticalevents/CriticalEventLog.java b/services/core/java/com/android/server/criticalevents/CriticalEventLog.java
index 816c349..036284f 100644
--- a/services/core/java/com/android/server/criticalevents/CriticalEventLog.java
+++ b/services/core/java/com/android/server/criticalevents/CriticalEventLog.java
@@ -30,6 +30,7 @@
 import com.android.server.criticalevents.nano.CriticalEventProto.AppNotResponding;
 import com.android.server.criticalevents.nano.CriticalEventProto.HalfWatchdog;
 import com.android.server.criticalevents.nano.CriticalEventProto.InstallPackages;
+import com.android.server.criticalevents.nano.CriticalEventProto.ExcessiveBinderCalls;
 import com.android.server.criticalevents.nano.CriticalEventProto.JavaCrash;
 import com.android.server.criticalevents.nano.CriticalEventProto.NativeCrash;
 import com.android.server.criticalevents.nano.CriticalEventProto.SystemServerStarted;
@@ -143,6 +144,15 @@
         return System.currentTimeMillis();
     }
 
+   /** Logs when a uid sends an excessive number of binder calls. */
+    public void logExcessiveBinderCalls(int uid) {
+        CriticalEventProto event = new CriticalEventProto();
+        ExcessiveBinderCalls calls = new ExcessiveBinderCalls();
+        calls.uid = uid;
+        event.setExcessiveBinderCalls(calls);
+        log(event);
+    }
+
     /** Logs when one or more packages are installed. */
     public void logInstallPackagesStarted() {
         CriticalEventProto event = new CriticalEventProto();
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 082776a..b2a738f 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -16,6 +16,7 @@
 
 package com.android.server.display;
 
+import static com.android.server.display.BrightnessMappingStrategy.INVALID_LUX;
 import static com.android.server.display.config.DisplayBrightnessMappingConfig.autoBrightnessModeToString;
 
 import android.annotation.IntDef;
@@ -202,7 +203,7 @@
     private float mScreenBrighteningThreshold;
     private float mScreenDarkeningThreshold;
     // The most recent light sample.
-    private float mLastObservedLux;
+    private float mLastObservedLux = INVALID_LUX;
 
     // The time of the most light recent sample.
     private long mLastObservedLuxTime;
@@ -403,8 +404,8 @@
             brightnessEvent.setFlags(brightnessEvent.getFlags()
                     | (!mAmbientLuxValid ? BrightnessEvent.FLAG_INVALID_LUX : 0)
                     | (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE
-                        ? BrightnessEvent.FLAG_DOZE_SCALE : 0)
-                    | (isInIdleMode() ? BrightnessEvent.FLAG_IDLE_CURVE : 0));
+                        ? BrightnessEvent.FLAG_DOZE_SCALE : 0));
+            brightnessEvent.setAutoBrightnessMode(getMode());
         }
 
         if (!mAmbientLuxValid) {
@@ -420,6 +421,35 @@
         return mRawScreenAutoBrightness;
     }
 
+    /**
+     * Get the automatic screen brightness based on the last observed lux reading. Used e.g. when
+     * entering doze - we disable the light sensor, invalidate the lux, but we still need to set
+     * the initial brightness in doze mode.
+     */
+    public float getAutomaticScreenBrightnessBasedOnLastObservedLux(
+            BrightnessEvent brightnessEvent) {
+        if (mLastObservedLux == INVALID_LUX) {
+            return PowerManager.BRIGHTNESS_INVALID_FLOAT;
+        }
+
+        float brightness = mCurrentBrightnessMapper.getBrightness(mLastObservedLux,
+                mForegroundAppPackageName, mForegroundAppCategory);
+        if (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE) {
+            brightness *= mDozeScaleFactor;
+        }
+
+        if (brightnessEvent != null) {
+            brightnessEvent.setLux(mLastObservedLux);
+            brightnessEvent.setRecommendedBrightness(brightness);
+            brightnessEvent.setFlags(brightnessEvent.getFlags()
+                    | (mLastObservedLux == INVALID_LUX ? BrightnessEvent.FLAG_INVALID_LUX : 0)
+                    | (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE
+                    ? BrightnessEvent.FLAG_DOZE_SCALE : 0));
+            brightnessEvent.setAutoBrightnessMode(getMode());
+        }
+        return brightness;
+    }
+
     public boolean hasValidAmbientLux() {
         return mAmbientLuxValid;
     }
@@ -433,12 +463,6 @@
             boolean userChangedAutoBrightnessAdjustment, int displayPolicy,
             boolean shouldResetShortTermModel) {
         mState = state;
-        // While dozing, the application processor may be suspended which will prevent us from
-        // receiving new information from the light sensor. On some devices, we may be able to
-        // switch to a wake-up light sensor instead but for now we will simply disable the sensor
-        // and hold onto the last computed screen auto brightness.  We save the dozing flag for
-        // debugging purposes.
-        boolean dozing = (displayPolicy == DisplayPowerRequest.POLICY_DOZE);
         boolean changed = setBrightnessConfiguration(configuration, shouldResetShortTermModel);
         changed |= setDisplayPolicy(displayPolicy);
         if (userChangedAutoBrightnessAdjustment) {
@@ -452,10 +476,10 @@
         }
         final boolean userInitiatedChange =
                 userChangedBrightness || userChangedAutoBrightnessAdjustment;
-        if (userInitiatedChange && enable && !dozing) {
+        if (userInitiatedChange && enable) {
             prepareBrightnessAdjustmentSample();
         }
-        changed |= setLightSensorEnabled(enable && !dozing);
+        changed |= setLightSensorEnabled(enable);
 
         if (mIsBrightnessThrottled != mBrightnessThrottler.isThrottled()) {
             // Maximum brightness has changed, so recalculate display brightness.
@@ -539,7 +563,7 @@
     }
 
     private boolean setScreenBrightnessByUser(float lux, float brightness) {
-        if (lux == BrightnessMappingStrategy.INVALID_LUX || Float.isNaN(brightness)) {
+        if (lux == INVALID_LUX || Float.isNaN(brightness)) {
             return false;
         }
         mCurrentBrightnessMapper.addUserDataPoint(lux, brightness);
@@ -564,6 +588,15 @@
         return false;
     }
 
+    /**
+     * @return The auto-brightness mode of the current mapping strategy. Different modes use
+     * different brightness curves.
+     */
+    @AutomaticBrightnessController.AutomaticBrightnessMode
+    public int getMode() {
+        return mCurrentBrightnessMapper.getMode();
+    }
+
     public boolean isInIdleMode() {
         return mCurrentBrightnessMapper.getMode() == AUTO_BRIGHTNESS_MODE_IDLE;
     }
@@ -1236,12 +1269,12 @@
         // light.
         // The anchor determines what were the light levels when the user has set their preference,
         // and we use a relative threshold to determine when to revert to the OEM curve.
-        private float mAnchor = BrightnessMappingStrategy.INVALID_LUX;
+        private float mAnchor = INVALID_LUX;
         private float mBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
         private boolean mIsValid = false;
 
         private void reset() {
-            mAnchor = BrightnessMappingStrategy.INVALID_LUX;
+            mAnchor = INVALID_LUX;
             mBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
             mIsValid = false;
         }
@@ -1265,7 +1298,7 @@
         private boolean maybeReset(float currentLux) {
             // If the short term model was invalidated and the change is drastic enough, reset it.
             // Otherwise, we revalidate it.
-            if (!mIsValid && mAnchor != BrightnessMappingStrategy.INVALID_LUX) {
+            if (!mIsValid && mAnchor != INVALID_LUX) {
                 if (mCurrentBrightnessMapper.shouldResetShortTermModel(currentLux, mAnchor)) {
                     resetShortTermModel();
                 } else {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 3965d55..2010aca 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -16,6 +16,8 @@
 
 package com.android.server.display;
 
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE;
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE;
@@ -37,7 +39,6 @@
 import android.hardware.display.BrightnessChangeEvent;
 import android.hardware.display.BrightnessConfiguration;
 import android.hardware.display.BrightnessInfo;
-import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.DisplayManagerInternal.DisplayOffloadSession;
 import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
 import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
@@ -1378,7 +1379,7 @@
         // Switch to doze auto-brightness mode if needed
         if (mFlags.areAutoBrightnessModesEnabled() && mAutomaticBrightnessController != null
                 && !mAutomaticBrightnessController.isInIdleMode()) {
-            setAutomaticScreenBrightnessMode(Display.isDozeState(state)
+            mAutomaticBrightnessController.switchMode(mPowerRequest.policy == POLICY_DOZE
                     ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT);
         }
 
@@ -1466,9 +1467,25 @@
             mAutomaticBrightnessStrategy.setAutoBrightnessApplied(false);
         }
 
+        // If there's an offload session and auto-brightness is on, we need to set the initial doze
+        // brightness using the doze auto-brightness curve before the offload session starts
+        // controlling the brightness.
+        if (Float.isNaN(brightnessState) && mFlags.areAutoBrightnessModesEnabled()
+                && mFlags.isDisplayOffloadEnabled()
+                && mPowerRequest.policy == POLICY_DOZE
+                && mDisplayOffloadSession != null
+                && mAutomaticBrightnessController != null
+                && mAutomaticBrightnessStrategy.shouldUseAutoBrightness()) {
+            rawBrightnessState = mAutomaticBrightnessController
+                    .getAutomaticScreenBrightnessBasedOnLastObservedLux(mTempBrightnessEvent);
+            if (BrightnessUtils.isValidBrightnessValue(rawBrightnessState)) {
+                brightnessState = clampScreenBrightness(rawBrightnessState);
+                mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_INITIAL);
+            }
+        }
+
         // Use default brightness when dozing unless overridden.
-        if ((Float.isNaN(brightnessState))
-                && Display.isDozeState(state)) {
+        if (Float.isNaN(brightnessState) && mPowerRequest.policy == POLICY_DOZE) {
             rawBrightnessState = mScreenBrightnessDozeConfig;
             brightnessState = clampScreenBrightness(rawBrightnessState);
             mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_DEFAULT);
@@ -1618,7 +1635,7 @@
 
             // if doze or suspend state is requested, we want to finish brightnes animation fast
             // to allow state animation to start
-            if (mPowerRequest.policy == DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE
+            if (mPowerRequest.policy == POLICY_DOZE
                     && (mPowerRequest.dozeScreenState == Display.STATE_UNKNOWN  // dozing
                     || mPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND
                     || mPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND)) {
@@ -1706,6 +1723,8 @@
         mTempBrightnessEvent.setTime(System.currentTimeMillis());
         mTempBrightnessEvent.setBrightness(brightnessState);
         mTempBrightnessEvent.setPhysicalDisplayId(mUniqueDisplayId);
+        mTempBrightnessEvent.setDisplayState(state);
+        mTempBrightnessEvent.setDisplayPolicy(mPowerRequest.policy);
         mTempBrightnessEvent.setReason(mBrightnessReason);
         mTempBrightnessEvent.setHbmMax(mBrightnessRangeController.getCurrentBrightnessMax());
         mTempBrightnessEvent.setHbmMode(mBrightnessRangeController.getHighBrightnessMode());
@@ -2879,7 +2898,7 @@
                     (flags & BrightnessEvent.FLAG_INVALID_LUX) > 0,
                     (flags & BrightnessEvent.FLAG_DOZE_SCALE) > 0,
                     (flags & BrightnessEvent.FLAG_USER_SET) > 0,
-                    (flags & BrightnessEvent.FLAG_IDLE_CURVE) > 0,
+                    event.getAutoBrightnessMode() == AUTO_BRIGHTNESS_MODE_IDLE,
                     (flags & BrightnessEvent.FLAG_LOW_POWER_MODE) > 0);
         }
     }
diff --git a/services/core/java/com/android/server/display/brightness/BrightnessEvent.java b/services/core/java/com/android/server/display/brightness/BrightnessEvent.java
index d4d1bae..82b401a 100644
--- a/services/core/java/com/android/server/display/brightness/BrightnessEvent.java
+++ b/services/core/java/com/android/server/display/brightness/BrightnessEvent.java
@@ -16,11 +16,19 @@
 
 package com.android.server.display.brightness;
 
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.policyToString;
+
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
+import static com.android.server.display.config.DisplayBrightnessMappingConfig.autoBrightnessModeToString;
+
 import android.hardware.display.BrightnessInfo;
 import android.os.PowerManager;
 import android.os.SystemClock;
+import android.view.Display;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.AutomaticBrightnessController;
 
 import java.text.SimpleDateFormat;
 import java.util.Date;
@@ -33,7 +41,6 @@
     public static final int FLAG_INVALID_LUX = 0x2;
     public static final int FLAG_DOZE_SCALE = 0x4;
     public static final int FLAG_USER_SET = 0x8;
-    public static final int FLAG_IDLE_CURVE = 0x10;
     public static final int FLAG_LOW_POWER_MODE = 0x20;
 
     private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
@@ -41,6 +48,8 @@
     private BrightnessReason mReason = new BrightnessReason();
     private int mDisplayId;
     private String mPhysicalDisplayId;
+    private int mDisplayState;
+    private int mDisplayPolicy;
     private long mTime;
     private float mLux;
     private float mPreThresholdLux;
@@ -58,6 +67,8 @@
     private int mAdjustmentFlags;
     private boolean mAutomaticBrightnessEnabled;
     private String mDisplayBrightnessStrategyName;
+    @AutomaticBrightnessController.AutomaticBrightnessMode
+    private int mAutoBrightnessMode;
 
     public BrightnessEvent(BrightnessEvent that) {
         copyFrom(that);
@@ -77,6 +88,8 @@
         mReason.set(that.getReason());
         mDisplayId = that.getDisplayId();
         mPhysicalDisplayId = that.getPhysicalDisplayId();
+        mDisplayState = that.mDisplayState;
+        mDisplayPolicy = that.mDisplayPolicy;
         mTime = that.getTime();
         // Lux values
         mLux = that.getLux();
@@ -98,6 +111,7 @@
         // Auto-brightness setting
         mAutomaticBrightnessEnabled = that.isAutomaticBrightnessEnabled();
         mDisplayBrightnessStrategyName = that.getDisplayBrightnessStrategyName();
+        mAutoBrightnessMode = that.mAutoBrightnessMode;
     }
 
     /**
@@ -107,6 +121,8 @@
         mReason = new BrightnessReason();
         mTime = SystemClock.uptimeMillis();
         mPhysicalDisplayId = "";
+        mDisplayState = Display.STATE_UNKNOWN;
+        mDisplayPolicy = POLICY_OFF;
         // Lux values
         mLux = 0;
         mPreThresholdLux = 0;
@@ -127,6 +143,7 @@
         // Auto-brightness setting
         mAutomaticBrightnessEnabled = true;
         mDisplayBrightnessStrategyName = "";
+        mAutoBrightnessMode = AUTO_BRIGHTNESS_MODE_DEFAULT;
     }
 
     /**
@@ -143,6 +160,8 @@
         return mReason.equals(that.mReason)
                 && mDisplayId == that.mDisplayId
                 && mPhysicalDisplayId.equals(that.mPhysicalDisplayId)
+                && mDisplayState == that.mDisplayState
+                && mDisplayPolicy == that.mDisplayPolicy
                 && Float.floatToRawIntBits(mLux) == Float.floatToRawIntBits(that.mLux)
                 && Float.floatToRawIntBits(mPreThresholdLux)
                 == Float.floatToRawIntBits(that.mPreThresholdLux)
@@ -163,7 +182,8 @@
                 && mFlags == that.mFlags
                 && mAdjustmentFlags == that.mAdjustmentFlags
                 && mAutomaticBrightnessEnabled == that.mAutomaticBrightnessEnabled
-                && mDisplayBrightnessStrategyName.equals(that.mDisplayBrightnessStrategyName);
+                && mDisplayBrightnessStrategyName.equals(that.mDisplayBrightnessStrategyName)
+                && mAutoBrightnessMode == that.mAutoBrightnessMode;
     }
 
     /**
@@ -177,6 +197,8 @@
                 + "BrightnessEvent: "
                 + "disp=" + mDisplayId
                 + ", physDisp=" + mPhysicalDisplayId
+                + ", displayState=" + Display.stateToString(mDisplayState)
+                + ", displayPolicy=" + policyToString(mDisplayPolicy)
                 + ", brt=" + mBrightness + ((mFlags & FLAG_USER_SET) != 0 ? "(user_set)" : "")
                 + ", initBrt=" + mInitialBrightness
                 + ", rcmdBrt=" + mRecommendedBrightness
@@ -192,7 +214,8 @@
                 + ", flags=" + flagsToString()
                 + ", reason=" + mReason.toString(mAdjustmentFlags)
                 + ", autoBrightness=" + mAutomaticBrightnessEnabled
-                + ", strategy=" + mDisplayBrightnessStrategyName;
+                + ", strategy=" + mDisplayBrightnessStrategyName
+                + ", autoBrightnessMode=" + autoBrightnessModeToString(mAutoBrightnessMode);
     }
 
     @Override
@@ -232,6 +255,14 @@
         this.mPhysicalDisplayId = mPhysicalDisplayId;
     }
 
+    public void setDisplayState(int state) {
+        mDisplayState = state;
+    }
+
+    public void setDisplayPolicy(int policy) {
+        mDisplayPolicy = policy;
+    }
+
     public float getLux() {
         return mLux;
     }
@@ -374,6 +405,16 @@
         this.mAutomaticBrightnessEnabled = mAutomaticBrightnessEnabled;
     }
 
+    @AutomaticBrightnessController.AutomaticBrightnessMode
+    public int getAutoBrightnessMode() {
+        return mAutoBrightnessMode;
+    }
+
+    public void setAutoBrightnessMode(
+            @AutomaticBrightnessController.AutomaticBrightnessMode int mode) {
+        mAutoBrightnessMode = mode;
+    }
+
     /**
      * A utility to stringify flags from a BrightnessEvent
      * @return Stringified flags from BrightnessEvent
@@ -384,7 +425,6 @@
                 + ((mFlags & FLAG_RBC) != 0 ? "rbc " : "")
                 + ((mFlags & FLAG_INVALID_LUX) != 0 ? "invalid_lux " : "")
                 + ((mFlags & FLAG_DOZE_SCALE) != 0 ? "doze_scale " : "")
-                + ((mFlags & FLAG_IDLE_CURVE) != 0 ? "idle_curve " : "")
                 + ((mFlags & FLAG_LOW_POWER_MODE) != 0 ? "low_power_mode " : "");
     }
 }
diff --git a/services/core/java/com/android/server/display/brightness/BrightnessReason.java b/services/core/java/com/android/server/display/brightness/BrightnessReason.java
index bc443a8..fc95d15 100644
--- a/services/core/java/com/android/server/display/brightness/BrightnessReason.java
+++ b/services/core/java/com/android/server/display/brightness/BrightnessReason.java
@@ -40,7 +40,8 @@
     public static final int REASON_SCREEN_OFF_BRIGHTNESS_SENSOR = 9;
     public static final int REASON_FOLLOWER = 10;
     public static final int REASON_OFFLOAD = 11;
-    public static final int REASON_MAX = REASON_OFFLOAD;
+    public static final int REASON_DOZE_INITIAL = 12;
+    public static final int REASON_MAX = REASON_DOZE_INITIAL;
 
     public static final int MODIFIER_DIMMED = 0x1;
     public static final int MODIFIER_LOW_POWER = 0x2;
@@ -207,6 +208,8 @@
                 return "follower";
             case REASON_OFFLOAD:
                 return "offload";
+            case REASON_DOZE_INITIAL:
+                return "doze_initial";
             default:
                 return Integer.toString(reason);
         }
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
index 055f94a..8e84450 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
@@ -71,6 +71,8 @@
     @Nullable
     private final OffloadBrightnessStrategy mOffloadBrightnessStrategy;
 
+    private final DisplayBrightnessStrategy[] mDisplayBrightnessStrategies;
+
     // We take note of the old brightness strategy so that we can know when the strategy changes.
     private String mOldBrightnessStrategyName;
 
@@ -98,6 +100,10 @@
         } else {
             mOffloadBrightnessStrategy = null;
         }
+        mDisplayBrightnessStrategies = new DisplayBrightnessStrategy[]{mInvalidBrightnessStrategy,
+                mScreenOffBrightnessStrategy, mDozeBrightnessStrategy, mFollowerBrightnessStrategy,
+                mBoostBrightnessStrategy, mOverrideBrightnessStrategy, mTemporaryBrightnessStrategy,
+                mOffloadBrightnessStrategy};
         mAllowAutoBrightnessWhileDozingConfig = context.getResources().getBoolean(
                 R.bool.config_allowAutoBrightnessWhileDozing);
         mOldBrightnessStrategyName = mInvalidBrightnessStrategy.getName();
@@ -179,9 +185,10 @@
                 "  mAllowAutoBrightnessWhileDozingConfig= "
                         + mAllowAutoBrightnessWhileDozingConfig);
         IndentingPrintWriter ipw = new IndentingPrintWriter(writer, " ");
-        mTemporaryBrightnessStrategy.dump(ipw);
-        if (mOffloadBrightnessStrategy != null) {
-            mOffloadBrightnessStrategy.dump(ipw);
+        for (DisplayBrightnessStrategy displayBrightnessStrategy: mDisplayBrightnessStrategies) {
+            if (displayBrightnessStrategy != null) {
+                displayBrightnessStrategy.dump(ipw);
+            }
         }
     }
 
@@ -193,12 +200,9 @@
         // We are not checking the targetDisplayState, but rather relying on the policy because
         // a user can define a different display state(displayPowerRequest.dozeScreenState) too
         // in the request with the Doze policy
-        if (displayPowerRequest.policy == DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE) {
-            if (!mAllowAutoBrightnessWhileDozingConfig) {
-                return true;
-            }
-        }
-        return false;
+        return displayPowerRequest.policy == DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE
+                && !mAllowAutoBrightnessWhileDozingConfig
+                && BrightnessUtils.isValidBrightnessValue(displayPowerRequest.dozeScreenBrightness);
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
index 3e6e09d..d1ca49b 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
@@ -15,6 +15,8 @@
  */
 package com.android.server.display.brightness.strategy;
 
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+
 import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.display.BrightnessConfiguration;
@@ -102,8 +104,7 @@
             boolean allowAutoBrightnessWhileDozingConfig, int brightnessReason, int policy,
             float lastUserSetScreenBrightness, boolean userSetBrightnessChanged) {
         final boolean autoBrightnessEnabledInDoze =
-                allowAutoBrightnessWhileDozingConfig
-                        && Display.isDozeState(targetDisplayState);
+                allowAutoBrightnessWhileDozingConfig && policy == POLICY_DOZE;
         mIsAutoBrightnessEnabled = shouldUseAutoBrightness()
                 && (targetDisplayState == Display.STATE_ON || autoBrightnessEnabledInDoze)
                 && brightnessReason != BrightnessReason.REASON_OVERRIDE
@@ -267,6 +268,23 @@
     }
 
     /**
+     * Get the automatic screen brightness based on the last observed lux reading. Used e.g. when
+     * entering doze - we disable the light sensor, invalidate the lux, but we still need to set
+     * the initial brightness in doze mode.
+     * @param brightnessEvent Event object to populate with details about why the specific
+     *                        brightness was chosen.
+     */
+    public float getAutomaticScreenBrightnessBasedOnLastObservedLux(
+            BrightnessEvent brightnessEvent) {
+        float brightness = (mAutomaticBrightnessController != null)
+                ? mAutomaticBrightnessController
+                .getAutomaticScreenBrightnessBasedOnLastObservedLux(brightnessEvent)
+                : PowerManager.BRIGHTNESS_INVALID_FLOAT;
+        adjustAutomaticBrightnessStateIfValid(brightness);
+        return brightness;
+    }
+
+    /**
      * Gets the auto-brightness adjustment flag change reason
      */
     public int getAutoBrightnessAdjustmentReasonsFlags() {
diff --git a/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java
index dd400d9..9ee1d73 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java
@@ -23,6 +23,8 @@
 import com.android.server.display.brightness.BrightnessReason;
 import com.android.server.display.brightness.BrightnessUtils;
 
+import java.io.PrintWriter;
+
 /**
  * Manages the brightness of the display when the system brightness boost is requested.
  */
@@ -48,4 +50,7 @@
     public String getName() {
         return "BoostBrightnessStrategy";
     }
+
+    @Override
+    public void dump(PrintWriter writer) {}
 }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategy.java
index 27d04fd..1f28eb4 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategy.java
@@ -21,6 +21,8 @@
 
 import com.android.server.display.DisplayBrightnessState;
 
+import java.io.PrintWriter;
+
 /**
  * Decides the DisplayBrighntessState that the display should change to based on strategy-specific
  * logic within each implementation. Clamping should be done outside of DisplayBrightnessStrategy if
@@ -40,4 +42,10 @@
      */
     @NonNull
     String getName();
+
+    /**
+     * Dumps the state of the Strategy
+     * @param writer
+     */
+    void dump(PrintWriter writer);
 }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java
index 8299586..2be7443 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java
@@ -22,6 +22,8 @@
 import com.android.server.display.brightness.BrightnessReason;
 import com.android.server.display.brightness.BrightnessUtils;
 
+import java.io.PrintWriter;
+
 /**
  * Manages the brightness of the display when the system is in the doze state.
  */
@@ -42,4 +44,6 @@
         return "DozeBrightnessStrategy";
     }
 
+    @Override
+    public void dump(PrintWriter writer) {}
 }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java
index 585f576..54f9afc 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java
@@ -75,6 +75,7 @@
     /**
      * Dumps the state of this class.
      */
+    @Override
     public void dump(PrintWriter writer) {
         writer.println("FollowerBrightnessStrategy:");
         writer.println("  mDisplayId=" + mDisplayId);
diff --git a/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java
index bc24196..49c3e03 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java
@@ -23,6 +23,8 @@
 import com.android.server.display.brightness.BrightnessReason;
 import com.android.server.display.brightness.BrightnessUtils;
 
+import java.io.PrintWriter;
+
 /**
  * Manages the brightness of the display when the system is in the invalid state.
  */
@@ -39,4 +41,7 @@
     public String getName() {
         return "InvalidBrightnessStrategy";
     }
+
+    @Override
+    public void dump(PrintWriter writer) {}
 }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java
index 55f8914..4ffb16b 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java
@@ -67,6 +67,7 @@
     /**
      * Dumps the state of this class.
      */
+    @Override
     public void dump(PrintWriter writer) {
         writer.println("OffloadBrightnessStrategy:");
         writer.println("  mOffloadScreenBrightness:" + mOffloadScreenBrightness);
diff --git a/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
index 13327cb..7b651d8 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
@@ -22,6 +22,8 @@
 import com.android.server.display.brightness.BrightnessReason;
 import com.android.server.display.brightness.BrightnessUtils;
 
+import java.io.PrintWriter;
+
 /**
  * Manages the brightness of the display when the system brightness is overridden
  */
@@ -40,4 +42,7 @@
     public String getName() {
         return "OverrideBrightnessStrategy";
     }
+
+    @Override
+    public void dump(PrintWriter writer) {}
 }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java
index 3d411d3..201ef41 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java
@@ -23,6 +23,8 @@
 import com.android.server.display.brightness.BrightnessReason;
 import com.android.server.display.brightness.BrightnessUtils;
 
+import java.io.PrintWriter;
+
 /**
  * Manages the brightness of the display when the system is in the ScreenOff state.
  */
@@ -41,4 +43,7 @@
     public String getName() {
         return "ScreenOffBrightnessStrategy";
     }
+
+    @Override
+    public void dump(PrintWriter writer) {}
 }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
index 35f7dd0..bbd0c00 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
@@ -68,6 +68,7 @@
     /**
      * Dumps the state of this class.
      */
+    @Override
     public void dump(PrintWriter writer) {
         writer.println("TemporaryBrightnessStrategy:");
         writer.println("  mTemporaryScreenBrightness:" + mTemporaryScreenBrightness);
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index d2aff25..c6d66db 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -67,6 +67,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.UiEventLoggerImpl;
 import com.android.internal.util.DumpUtils;
@@ -112,7 +113,7 @@
     private final Object mLock = new Object();
 
     private final Context mContext;
-    private final DreamHandler mHandler;
+    private final Handler mHandler;
     private final DreamController mController;
     private final PowerManager mPowerManager;
     private final PowerManagerInternal mPowerManagerInternal;
@@ -211,9 +212,14 @@
     }
 
     public DreamManagerService(Context context) {
+        this(context, new DreamHandler(FgThread.get().getLooper()));
+    }
+
+    @VisibleForTesting
+    DreamManagerService(Context context, Handler handler) {
         super(context);
         mContext = context;
-        mHandler = new DreamHandler(FgThread.get().getLooper());
+        mHandler = handler;
         mController = new DreamController(context, mHandler, mControllerListener);
 
         mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
@@ -244,7 +250,6 @@
                 com.android.internal.R.bool.config_keepDreamingWhenUnplugging);
         mDreamsDisabledByAmbientModeSuppressionConfig = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_dreamsDisabledByAmbientModeSuppressionConfig);
-
     }
 
     @Override
diff --git a/services/core/java/com/android/server/flags/services.aconfig b/services/core/java/com/android/server/flags/services.aconfig
new file mode 100644
index 0000000..10b5eff
--- /dev/null
+++ b/services/core/java/com/android/server/flags/services.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.server.flags"
+
+flag {
+     namespace: "wear_frameworks"
+     name: "enable_odp_feature_guard"
+     description: "Enable guard based on system feature to prevent OnDevicePersonalization service from starting on form factors."
+     bug: "322249125"
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 70993ca..1e90ab2 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -317,6 +317,10 @@
         if ((systemAudioOnPowerOnProp == ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON)
                 || ((systemAudioOnPowerOnProp == USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON)
                 && lastSystemAudioControlStatus && isSystemAudioControlFeatureEnabled())) {
+            if (hasAction(SystemAudioInitiationActionFromAvr.class)) {
+                Slog.i(TAG, "SystemAudioInitiationActionFromAvr is in progress. Restarting.");
+                removeAction(SystemAudioInitiationActionFromAvr.class);
+            }
             addAndStartAction(new SystemAudioInitiationActionFromAvr(this));
         }
     }
@@ -1032,6 +1036,10 @@
     void onSystemAudioControlFeatureSupportChanged(boolean enabled) {
         setSystemAudioControlFeatureEnabled(enabled);
         if (enabled) {
+            if (hasAction(SystemAudioInitiationActionFromAvr.class)) {
+                Slog.i(TAG, "SystemAudioInitiationActionFromAvr is in progress. Restarting.");
+                removeAction(SystemAudioInitiationActionFromAvr.class);
+            }
             addAndStartAction(new SystemAudioInitiationActionFromAvr(this));
         }
     }
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 32e89bc..05b1cb69 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -38,7 +38,6 @@
 import android.hardware.SensorPrivacyManager;
 import android.hardware.SensorPrivacyManager.Sensors;
 import android.hardware.SensorPrivacyManagerInternal;
-import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.DisplayViewport;
 import android.hardware.input.HostUsiVersion;
@@ -55,6 +54,7 @@
 import android.hardware.input.InputSensorInfo;
 import android.hardware.input.InputSettings;
 import android.hardware.input.KeyboardLayout;
+import android.hardware.input.KeyboardLayoutSelectionResult;
 import android.hardware.input.TouchCalibration;
 import android.hardware.lights.Light;
 import android.hardware.lights.LightState;
@@ -86,9 +86,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
 import android.view.Display;
-import android.view.DisplayInfo;
 import android.view.IInputFilter;
 import android.view.IInputFilterHost;
 import android.view.IInputMonitorHost;
@@ -324,6 +322,9 @@
     // Manages Keyboard modifier keys remapping
     private final KeyRemapper mKeyRemapper;
 
+    // Manages loading PointerIcons
+    private final PointerIconCache mPointerIconCache;
+
     // Maximum number of milliseconds to wait for input event injection.
     private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
 
@@ -410,74 +411,6 @@
     private boolean mShowKeyPresses = false;
     private boolean mShowRotaryInput = false;
 
-    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
-    final SparseArray<SparseArray<PointerIcon>> mLoadedPointerIconsByDisplayAndType =
-            new SparseArray<>();
-    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
-    boolean mUseLargePointerIcons = false;
-    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
-    final SparseArray<Context> mDisplayContexts = new SparseArray<>();
-    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
-    final SparseIntArray mDisplayDensities = new SparseIntArray();
-
-    final DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() {
-        @Override
-        public void onDisplayAdded(int displayId) {
-            synchronized (mLoadedPointerIconsByDisplayAndType) {
-                updateDisplayDensity(displayId);
-            }
-        }
-
-        @Override
-        public void onDisplayRemoved(int displayId) {
-            synchronized (mLoadedPointerIconsByDisplayAndType) {
-                mLoadedPointerIconsByDisplayAndType.remove(displayId);
-                mDisplayContexts.remove(displayId);
-                mDisplayDensities.delete(displayId);
-            }
-        }
-
-        @Override
-        public void onDisplayChanged(int displayId) {
-            synchronized (mLoadedPointerIconsByDisplayAndType) {
-                if (!updateDisplayDensity(displayId)) {
-                    return;
-                }
-                // The display density changed, so force all cached pointer icons to be
-                // reloaded for the display.
-                Slog.i(TAG,
-                        "Reloading pointer icons due to density change on display: " + displayId);
-                var iconsByType = mLoadedPointerIconsByDisplayAndType.get(displayId);
-                if (iconsByType == null) {
-                    return;
-                }
-                iconsByType.clear();
-                mDisplayContexts.remove(displayId);
-            }
-            mNative.reloadPointerIcons();
-        }
-
-        // Updates the cached display density for the given displayId, and returns true if
-        // the cached density changed.
-        @GuardedBy("mLoadedPointerIconsByDisplayAndType")
-        private boolean updateDisplayDensity(int displayId) {
-            final DisplayManager displayManager = Objects.requireNonNull(
-                    mContext.getSystemService(DisplayManager.class));
-            final Display display = displayManager.getDisplay(displayId);
-            if (display == null) {
-                return false;
-            }
-            DisplayInfo info = new DisplayInfo();
-            display.getDisplayInfo(info);
-            final int oldDensity = mDisplayDensities.get(displayId, 0 /* default */);
-            if (oldDensity == info.logicalDensityDpi) {
-                return false;
-            }
-            mDisplayDensities.put(displayId, info.logicalDensityDpi);
-            return true;
-        }
-    };
-
     /** Point of injection for test dependencies. */
     @VisibleForTesting
     static class Injector {
@@ -536,6 +469,7 @@
                 : new KeyboardBacklightControllerInterface() {};
         mStickyModifierStateController = new StickyModifierStateController();
         mKeyRemapper = new KeyRemapper(mContext, mNative, mDataStore, injector.getLooper());
+        mPointerIconCache = new PointerIconCache(mContext, mNative);
 
         mUseDevInputEventForAudioJack =
                 mContext.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
@@ -645,18 +579,11 @@
             mWiredAccessoryCallbacks.systemReady();
         }
 
-        final DisplayManager displayManager = Objects.requireNonNull(
-                mContext.getSystemService(DisplayManager.class));
-        displayManager.registerDisplayListener(mDisplayListener, mHandler);
-        final Display[] displays = displayManager.getDisplays();
-        for (int i = 0; i < displays.length; i++) {
-            mDisplayListener.onDisplayAdded(displays[i].getDisplayId());
-        }
-
         mKeyboardLayoutManager.systemRunning();
         mBatteryController.systemRunning();
         mKeyboardBacklightController.systemRunning();
         mKeyRemapper.systemRunning();
+        mPointerIconCache.systemRunning();
     }
 
     private void reloadDeviceAliases() {
@@ -1318,9 +1245,9 @@
     }
 
     @Override // Binder call
-    public String getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
-            @UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
-            @Nullable InputMethodSubtype imeSubtype) {
+    public KeyboardLayoutSelectionResult getKeyboardLayoutForInputDevice(
+            InputDeviceIdentifier identifier, @UserIdInt int userId,
+            @NonNull InputMethodInfo imeInfo, @Nullable InputMethodSubtype imeSubtype) {
         return mKeyboardLayoutManager.getKeyboardLayoutForInputDevice(identifier, userId,
                 imeInfo, imeSubtype);
     }
@@ -2410,8 +2337,8 @@
         synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ }
         synchronized (mInputMonitors) { /* Test if blocked by input monitor lock. */ }
         synchronized (mAdditionalDisplayInputPropertiesLock) { /* Test if blocked by props lock */ }
-        synchronized (mLoadedPointerIconsByDisplayAndType) { /* Test if blocked by pointer lock */}
         mBatteryController.monitor();
+        mPointerIconCache.monitor();
         mNative.monitor();
     }
 
@@ -2805,21 +2732,7 @@
     // Native callback.
     @SuppressWarnings("unused")
     private @NonNull PointerIcon getLoadedPointerIcon(int displayId, int type) {
-        synchronized (mLoadedPointerIconsByDisplayAndType) {
-            SparseArray<PointerIcon> iconsByType = mLoadedPointerIconsByDisplayAndType.get(
-                    displayId);
-            if (iconsByType == null) {
-                iconsByType = new SparseArray<>();
-                mLoadedPointerIconsByDisplayAndType.put(displayId, iconsByType);
-            }
-            PointerIcon icon = iconsByType.get(type);
-            if (icon == null) {
-                icon = PointerIcon.getLoadedSystemIcon(getContextForDisplay(displayId), type,
-                        mUseLargePointerIcons);
-                iconsByType.put(type, icon);
-            }
-            return Objects.requireNonNull(icon);
-        }
+        return mPointerIconCache.getLoadedPointerIcon(displayId, type);
     }
 
     // Native callback.
@@ -2832,33 +2745,6 @@
         return sc.mNativeObject;
     }
 
-    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
-    @NonNull
-    private Context getContextForDisplay(int displayId) {
-        if (displayId == Display.INVALID_DISPLAY) {
-            // Fallback to using the default context.
-            return mContext;
-        }
-        if (displayId == mContext.getDisplay().getDisplayId()) {
-            return mContext;
-        }
-
-        Context displayContext = mDisplayContexts.get(displayId);
-        if (displayContext == null) {
-            final DisplayManager displayManager = Objects.requireNonNull(
-                    mContext.getSystemService(DisplayManager.class));
-            final Display display = displayManager.getDisplay(displayId);
-            if (display == null) {
-                // Fallback to using the default context.
-                return mContext;
-            }
-
-            displayContext = mContext.createDisplayContext(display);
-            mDisplayContexts.put(displayId, displayContext);
-        }
-        return displayContext;
-    }
-
     // Native callback.
     @SuppressWarnings("unused")
     private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier, String languageTag,
@@ -3664,15 +3550,7 @@
     }
 
     void setUseLargePointerIcons(boolean useLargeIcons) {
-        synchronized (mLoadedPointerIconsByDisplayAndType) {
-            if (mUseLargePointerIcons == useLargeIcons) {
-                return;
-            }
-            mUseLargePointerIcons = useLargeIcons;
-            // Clear all cached icons on all displays.
-            mLoadedPointerIconsByDisplayAndType.clear();
-        }
-        mNative.reloadPointerIcons();
+        mPointerIconCache.setUseLargePointerIcons(useLargeIcons);
     }
 
     interface KeyboardBacklightControllerInterface {
diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
index 46668de..283e692 100644
--- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java
+++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
@@ -16,10 +16,11 @@
 
 package com.android.server.input;
 
-import static com.android.server.input.KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEFAULT;
-import static com.android.server.input.KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEVICE;
-import static com.android.server.input.KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_USER;
-import static com.android.server.input.KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD;
+import static android.hardware.input.KeyboardLayoutSelectionResult.FAILED;
+import static android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_USER;
+import static android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEVICE;
+import static android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD;
+import static android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEFAULT;
 
 import android.annotation.AnyThread;
 import android.annotation.MainThread;
@@ -46,6 +47,7 @@
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
 import android.hardware.input.KeyboardLayout;
+import android.hardware.input.KeyboardLayoutSelectionResult;
 import android.icu.lang.UScript;
 import android.icu.util.ULocale;
 import android.os.Bundle;
@@ -79,7 +81,6 @@
 import com.android.server.LocalServices;
 import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
 import com.android.server.input.KeyboardMetricsCollector.KeyboardConfigurationEvent;
-import com.android.server.input.KeyboardMetricsCollector.LayoutSelectionCriteria;
 import com.android.server.inputmethod.InputMethodManagerInternal;
 
 import libcore.io.Streams;
@@ -130,7 +131,8 @@
     // This cache stores "best-matched" layouts so that we don't need to run the matching
     // algorithm repeatedly.
     @GuardedBy("mKeyboardLayoutCache")
-    private final Map<String, KeyboardLayoutInfo> mKeyboardLayoutCache = new ArrayMap<>();
+    private final Map<String, KeyboardLayoutSelectionResult> mKeyboardLayoutCache =
+            new ArrayMap<>();
     private final Object mImeInfoLock = new Object();
     @Nullable
     @GuardedBy("mImeInfoLock")
@@ -222,17 +224,17 @@
         } else {
             Set<String> selectedLayouts = new HashSet<>();
             List<ImeInfo> imeInfoList = getImeInfoListForLayoutMapping();
-            List<KeyboardLayoutInfo> layoutInfoList = new ArrayList<>();
+            List<KeyboardLayoutSelectionResult> resultList = new ArrayList<>();
             boolean hasMissingLayout = false;
             for (ImeInfo imeInfo : imeInfoList) {
                 // Check if the layout has been previously configured
-                KeyboardLayoutInfo layoutInfo = getKeyboardLayoutForInputDeviceInternal(
+                KeyboardLayoutSelectionResult result = getKeyboardLayoutForInputDeviceInternal(
                         keyboardIdentifier, imeInfo);
-                boolean noLayoutFound = layoutInfo == null || layoutInfo.mDescriptor == null;
+                boolean noLayoutFound = result.getLayoutDescriptor() == null;
                 if (!noLayoutFound) {
-                    selectedLayouts.add(layoutInfo.mDescriptor);
+                    selectedLayouts.add(result.getLayoutDescriptor());
                 }
-                layoutInfoList.add(layoutInfo);
+                resultList.add(result);
                 hasMissingLayout |= noLayoutFound;
             }
 
@@ -260,7 +262,7 @@
                     }
 
                     if (shouldLogConfiguration) {
-                        logKeyboardConfigurationEvent(inputDevice, imeInfoList, layoutInfoList,
+                        logKeyboardConfigurationEvent(inputDevice, imeInfoList, resultList,
                                 !mDataStore.hasInputDeviceEntry(key));
                     }
                 } finally {
@@ -757,10 +759,10 @@
         String keyboardLayoutDescriptor;
         if (useNewSettingsUi()) {
             synchronized (mImeInfoLock) {
-                KeyboardLayoutInfo layoutInfo = getKeyboardLayoutForInputDeviceInternal(
+                KeyboardLayoutSelectionResult result = getKeyboardLayoutForInputDeviceInternal(
                         new KeyboardIdentifier(identifier, languageTag, layoutType),
                         mCurrentImeInfo);
-                keyboardLayoutDescriptor = layoutInfo == null ? null : layoutInfo.mDescriptor;
+                keyboardLayoutDescriptor = result.getLayoutDescriptor();
             }
         } else {
             keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
@@ -788,26 +790,26 @@
     }
 
     @AnyThread
-    @Nullable
-    public String getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
-            @UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
-            @Nullable InputMethodSubtype imeSubtype) {
+    @NonNull
+    public KeyboardLayoutSelectionResult getKeyboardLayoutForInputDevice(
+            InputDeviceIdentifier identifier, @UserIdInt int userId,
+            @NonNull InputMethodInfo imeInfo, @Nullable InputMethodSubtype imeSubtype) {
         if (!useNewSettingsUi()) {
             Slog.e(TAG, "getKeyboardLayoutForInputDevice() API not supported");
-            return null;
+            return FAILED;
         }
         InputDevice inputDevice = getInputDevice(identifier);
         if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
-            return null;
+            return FAILED;
         }
         KeyboardIdentifier keyboardIdentifier = new KeyboardIdentifier(inputDevice);
-        KeyboardLayoutInfo layoutInfo = getKeyboardLayoutForInputDeviceInternal(
+        KeyboardLayoutSelectionResult result = getKeyboardLayoutForInputDeviceInternal(
                 keyboardIdentifier, new ImeInfo(userId, imeInfo, imeSubtype));
         if (DEBUG) {
             Slog.d(TAG, "getKeyboardLayoutForInputDevice() " + identifier.toString() + ", userId : "
-                    + userId + ", subtype = " + imeSubtype + " -> " + layoutInfo);
+                    + userId + ", subtype = " + imeSubtype + " -> " + result);
         }
-        return layoutInfo != null ? layoutInfo.mDescriptor : null;
+        return result;
     }
 
     @AnyThread
@@ -942,13 +944,13 @@
     }
 
     @Nullable
-    private KeyboardLayoutInfo getKeyboardLayoutForInputDeviceInternal(
+    private KeyboardLayoutSelectionResult getKeyboardLayoutForInputDeviceInternal(
             KeyboardIdentifier keyboardIdentifier, @Nullable ImeInfo imeInfo) {
         String layoutKey = new LayoutKey(keyboardIdentifier, imeInfo).toString();
         synchronized (mDataStore) {
             String layout = mDataStore.getKeyboardLayout(keyboardIdentifier.toString(), layoutKey);
             if (layout != null) {
-                return new KeyboardLayoutInfo(layout, LAYOUT_SELECTION_CRITERIA_USER);
+                return new KeyboardLayoutSelectionResult(layout, LAYOUT_SELECTION_CRITERIA_USER);
             }
         }
 
@@ -961,17 +963,17 @@
                 KeyboardLayout[] layoutList = getKeyboardLayoutListForInputDeviceInternal(
                         keyboardIdentifier, imeInfo);
                 // Call auto-matching algorithm to find the best matching layout
-                KeyboardLayoutInfo layoutInfo =
+                KeyboardLayoutSelectionResult result =
                         getDefaultKeyboardLayoutBasedOnImeInfo(keyboardIdentifier, imeInfo,
                                 layoutList);
-                mKeyboardLayoutCache.put(layoutKey, layoutInfo);
-                return layoutInfo;
+                mKeyboardLayoutCache.put(layoutKey, result);
+                return result;
             }
         }
     }
 
-    @Nullable
-    private static KeyboardLayoutInfo getDefaultKeyboardLayoutBasedOnImeInfo(
+    @NonNull
+    private static KeyboardLayoutSelectionResult getDefaultKeyboardLayoutBasedOnImeInfo(
             KeyboardIdentifier keyboardIdentifier, @Nullable ImeInfo imeInfo,
             KeyboardLayout[] layoutList) {
         Arrays.sort(layoutList);
@@ -986,7 +988,7 @@
                                     + "vendor and product Ids. " + keyboardIdentifier
                                     + " : " + layout.getDescriptor());
                 }
-                return new KeyboardLayoutInfo(layout.getDescriptor(),
+                return new KeyboardLayoutSelectionResult(layout.getDescriptor(),
                         LAYOUT_SELECTION_CRITERIA_DEVICE);
             }
         }
@@ -1004,13 +1006,14 @@
                                     + "HW information (Language tag and Layout type). "
                                     + keyboardIdentifier + " : " + layoutDesc);
                 }
-                return new KeyboardLayoutInfo(layoutDesc, LAYOUT_SELECTION_CRITERIA_DEVICE);
+                return new KeyboardLayoutSelectionResult(layoutDesc,
+                        LAYOUT_SELECTION_CRITERIA_DEVICE);
             }
         }
 
         if (imeInfo == null || imeInfo.mImeSubtypeHandle == null || imeInfo.mImeSubtype == null) {
             // Can't auto select layout based on IME info is null
-            return null;
+            return FAILED;
         }
 
         InputMethodSubtype subtype = imeInfo.mImeSubtype;
@@ -1027,9 +1030,10 @@
                             + layoutDesc);
         }
         if (layoutDesc != null) {
-            return new KeyboardLayoutInfo(layoutDesc, LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD);
+            return new KeyboardLayoutSelectionResult(layoutDesc,
+                    LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD);
         }
-        return null;
+        return FAILED;
     }
 
     @Nullable
@@ -1246,21 +1250,23 @@
     }
 
     private void logKeyboardConfigurationEvent(@NonNull InputDevice inputDevice,
-            @NonNull List<ImeInfo> imeInfoList, @NonNull List<KeyboardLayoutInfo> layoutInfoList,
+            @NonNull List<ImeInfo> imeInfoList,
+            @NonNull List<KeyboardLayoutSelectionResult> resultList,
             boolean isFirstConfiguration) {
-        if (imeInfoList.isEmpty() || layoutInfoList.isEmpty()) {
+        if (imeInfoList.isEmpty() || resultList.isEmpty()) {
             return;
         }
         KeyboardConfigurationEvent.Builder configurationEventBuilder =
                 new KeyboardConfigurationEvent.Builder(inputDevice).setIsFirstTimeConfiguration(
                         isFirstConfiguration);
         for (int i = 0; i < imeInfoList.size(); i++) {
-            KeyboardLayoutInfo layoutInfo = layoutInfoList.get(i);
+            KeyboardLayoutSelectionResult result = resultList.get(i);
             String layoutName = null;
             int layoutSelectionCriteria = LAYOUT_SELECTION_CRITERIA_DEFAULT;
-            if (layoutInfo != null && layoutInfo.mDescriptor != null) {
-                layoutSelectionCriteria = layoutInfo.mSelectionCriteria;
-                KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(layoutInfo.mDescriptor);
+            if (result != null && result.getLayoutDescriptor() != null) {
+                layoutSelectionCriteria = result.getSelectionCriteria();
+                KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(
+                        result.getLayoutDescriptor());
                 if (d != null) {
                     layoutName = d.keyboardLayoutName;
                 }
@@ -1477,33 +1483,6 @@
         }
     }
 
-    private static class KeyboardLayoutInfo {
-        @Nullable
-        private final String mDescriptor;
-        @LayoutSelectionCriteria
-        private final int mSelectionCriteria;
-
-        private KeyboardLayoutInfo(@Nullable String descriptor,
-                @LayoutSelectionCriteria int selectionCriteria) {
-            mDescriptor = descriptor;
-            mSelectionCriteria = selectionCriteria;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof KeyboardLayoutInfo) {
-                return Objects.equals(mDescriptor, ((KeyboardLayoutInfo) obj).mDescriptor)
-                        && mSelectionCriteria == ((KeyboardLayoutInfo) obj).mSelectionCriteria;
-            }
-            return false;
-        }
-
-        @Override
-        public int hashCode() {
-            return 31 * mSelectionCriteria + mDescriptor.hashCode();
-        }
-    }
-
     private interface KeyboardLayoutVisitor {
         void visitKeyboardLayout(Resources resources,
                 int keyboardLayoutResId, KeyboardLayout layout);
diff --git a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
index 4b9f2cf..b8ae737 100644
--- a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
+++ b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
@@ -16,13 +16,18 @@
 
 package com.android.server.input;
 
-import static java.lang.annotation.RetentionPolicy.SOURCE;
+import static android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_USER;
+import static android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEVICE;
+import static android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD;
+import static android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEFAULT;
+import static android.hardware.input.KeyboardLayoutSelectionResult.layoutSelectionCriteriaToString;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.role.RoleManager;
 import android.content.Intent;
 import android.hardware.input.KeyboardLayout;
+import android.hardware.input.KeyboardLayoutSelectionResult.LayoutSelectionCriteria;
 import android.icu.util.ULocale;
 import android.text.TextUtils;
 import android.util.Log;
@@ -37,8 +42,8 @@
 import com.android.internal.os.KeyboardConfiguredProto.KeyboardLayoutConfig;
 import com.android.internal.os.KeyboardConfiguredProto.RepeatedKeyboardLayoutConfig;
 import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.policy.ModifierShortcutManager;
 
-import java.lang.annotation.Retention;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -55,32 +60,6 @@
     // (requires restart)
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    @Retention(SOURCE)
-    @IntDef(prefix = {"LAYOUT_SELECTION_CRITERIA_"}, value = {
-            LAYOUT_SELECTION_CRITERIA_UNSPECIFIED,
-            LAYOUT_SELECTION_CRITERIA_USER,
-            LAYOUT_SELECTION_CRITERIA_DEVICE,
-            LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD,
-            LAYOUT_SELECTION_CRITERIA_DEFAULT
-    })
-    public @interface LayoutSelectionCriteria {
-    }
-
-    /** Unspecified layout selection criteria */
-    public static final int LAYOUT_SELECTION_CRITERIA_UNSPECIFIED = 0;
-
-    /** Manual selection by user */
-    public static final int LAYOUT_SELECTION_CRITERIA_USER = 1;
-
-    /** Auto-detection based on device provided language tag and layout type */
-    public static final int LAYOUT_SELECTION_CRITERIA_DEVICE = 2;
-
-    /** Auto-detection based on IME provided language tag and layout type */
-    public static final int LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD = 3;
-
-    /** Default selection */
-    public static final int LAYOUT_SELECTION_CRITERIA_DEFAULT = 4;
-
     @VisibleForTesting
     static final String DEFAULT_LAYOUT_NAME = "Default";
 
@@ -231,7 +210,10 @@
         DESKTOP_MODE(
                 FrameworkStatsLog
                         .KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__DESKTOP_MODE,
-                "DESKTOP_MODE");
+                "DESKTOP_MODE"),
+        MULTI_WINDOW_NAVIGATION(FrameworkStatsLog
+                .KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MULTI_WINDOW_NAVIGATION,
+                "MULTIWINDOW_NAVIGATION");
 
 
         private final int mValue;
@@ -315,6 +297,13 @@
                 }
             }
 
+            // The shortcut may be targeting a system role rather than using an intent selector,
+            // so check for that.
+            String role = intent.getStringExtra(ModifierShortcutManager.EXTRA_ROLE);
+            if (!TextUtils.isEmpty(role)) {
+                return getLogEventFromRole(role);
+            }
+
             Set<String> intentCategories = intent.getCategories();
             if (intentCategories == null || intentCategories.isEmpty()
                     || !intentCategories.contains(Intent.CATEGORY_LAUNCHER)) {
@@ -360,6 +349,23 @@
                     return null;
             }
         }
+
+        /**
+         * Find KeyboardLogEvent corresponding to the provide system role name.
+         * Returns {@code null} if no matching event found.
+         */
+        @Nullable
+        private static KeyboardLogEvent getLogEventFromRole(String role) {
+            if (RoleManager.ROLE_BROWSER.equals(role)) {
+                return LAUNCH_DEFAULT_BROWSER;
+            } else if (RoleManager.ROLE_SMS.equals(role)) {
+                return LAUNCH_DEFAULT_MESSAGING;
+            } else {
+                Log.w(TAG, "Keyboard shortcut to launch "
+                        + role + " not supported for logging");
+                return null;
+            }
+        }
     }
 
     /**
@@ -600,30 +606,16 @@
 
         @Override
         public String toString() {
-            return "{keyboardLanguageTag = " + keyboardLanguageTag + " keyboardLayoutType = "
+            return "{keyboardLanguageTag = " + keyboardLanguageTag
+                    + " keyboardLayoutType = "
                     + KeyboardLayout.LayoutType.getLayoutNameFromValue(keyboardLayoutType)
-                    + " keyboardLayoutName = " + keyboardLayoutName + " layoutSelectionCriteria = "
-                    + getStringForSelectionCriteria(layoutSelectionCriteria)
-                    + "imeLanguageTag = " + imeLanguageTag + " imeLayoutType = "
-                    + KeyboardLayout.LayoutType.getLayoutNameFromValue(imeLayoutType) + "}";
-        }
-    }
-
-    private static String getStringForSelectionCriteria(
-            @LayoutSelectionCriteria int layoutSelectionCriteria) {
-        switch (layoutSelectionCriteria) {
-            case LAYOUT_SELECTION_CRITERIA_UNSPECIFIED:
-                return "LAYOUT_SELECTION_CRITERIA_UNSPECIFIED";
-            case LAYOUT_SELECTION_CRITERIA_USER:
-                return "LAYOUT_SELECTION_CRITERIA_USER";
-            case LAYOUT_SELECTION_CRITERIA_DEVICE:
-                return "LAYOUT_SELECTION_CRITERIA_DEVICE";
-            case LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD:
-                return "LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD";
-            case LAYOUT_SELECTION_CRITERIA_DEFAULT:
-                return "LAYOUT_SELECTION_CRITERIA_DEFAULT";
-            default:
-                return "INVALID_CRITERIA";
+                    + " keyboardLayoutName = " + keyboardLayoutName
+                    + " layoutSelectionCriteria = "
+                    + layoutSelectionCriteriaToString(layoutSelectionCriteria)
+                    + " imeLanguageTag = " + imeLanguageTag
+                    + " imeLayoutType = " + KeyboardLayout.LayoutType.getLayoutNameFromValue(
+                    imeLayoutType)
+                    + "}";
         }
     }
 
diff --git a/services/core/java/com/android/server/input/PointerIconCache.java b/services/core/java/com/android/server/input/PointerIconCache.java
new file mode 100644
index 0000000..233b865
--- /dev/null
+++ b/services/core/java/com/android/server/input/PointerIconCache.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.input;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.PointerIcon;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.UiThread;
+
+import java.util.Objects;
+
+/**
+ * A thread-safe component of {@link InputManagerService} responsible for caching loaded
+ * {@link PointerIcon}s and triggering reloading of the icons.
+ */
+final class PointerIconCache {
+    private static final String TAG = PointerIconCache.class.getSimpleName();
+
+    private final Context mContext;
+
+    // Do not hold the lock when calling into native code.
+    private final NativeInputManagerService mNative;
+
+    // We use the UI thread for loading pointer icons.
+    private final Handler mUiThreadHandler = UiThread.getHandler();
+
+    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
+    private final SparseArray<SparseArray<PointerIcon>> mLoadedPointerIconsByDisplayAndType =
+            new SparseArray<>();
+    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
+    private boolean mUseLargePointerIcons = false;
+    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
+    private final SparseArray<Context> mDisplayContexts = new SparseArray<>();
+    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
+    private final SparseIntArray mDisplayDensities = new SparseIntArray();
+
+    private final DisplayManager.DisplayListener mDisplayListener =
+            new DisplayManager.DisplayListener() {
+                @Override
+                public void onDisplayAdded(int displayId) {
+                    synchronized (mLoadedPointerIconsByDisplayAndType) {
+                        updateDisplayDensityLocked(displayId);
+                    }
+                }
+
+                @Override
+                public void onDisplayRemoved(int displayId) {
+                    synchronized (mLoadedPointerIconsByDisplayAndType) {
+                        mLoadedPointerIconsByDisplayAndType.remove(displayId);
+                        mDisplayContexts.remove(displayId);
+                        mDisplayDensities.delete(displayId);
+                    }
+                }
+
+                @Override
+                public void onDisplayChanged(int displayId) {
+                    handleDisplayChanged(displayId);
+                }
+            };
+
+    /* package */ PointerIconCache(Context context, NativeInputManagerService nativeService) {
+        mContext = context;
+        mNative = nativeService;
+    }
+
+    public void systemRunning() {
+        final DisplayManager displayManager = Objects.requireNonNull(
+                mContext.getSystemService(DisplayManager.class));
+        displayManager.registerDisplayListener(mDisplayListener, mUiThreadHandler);
+        final Display[] displays = displayManager.getDisplays();
+        for (int i = 0; i < displays.length; i++) {
+            mDisplayListener.onDisplayAdded(displays[i].getDisplayId());
+        }
+    }
+
+    public void monitor() {
+        synchronized (mLoadedPointerIconsByDisplayAndType) { /* Test if blocked by lock */}
+    }
+
+    /** Set whether the large pointer icons should be used for accessibility. */
+    public void setUseLargePointerIcons(boolean useLargeIcons) {
+        mUiThreadHandler.post(() -> handleSetUseLargePointerIcons(useLargeIcons));
+    }
+
+    /**
+     * Get a loaded system pointer icon. This will fetch the icon from the cache, or load it if
+     * it isn't already cached.
+     */
+    public @NonNull PointerIcon getLoadedPointerIcon(int displayId, int type) {
+        synchronized (mLoadedPointerIconsByDisplayAndType) {
+            SparseArray<PointerIcon> iconsByType = mLoadedPointerIconsByDisplayAndType.get(
+                    displayId);
+            if (iconsByType == null) {
+                iconsByType = new SparseArray<>();
+                mLoadedPointerIconsByDisplayAndType.put(displayId, iconsByType);
+            }
+            PointerIcon icon = iconsByType.get(type);
+            if (icon == null) {
+                icon = PointerIcon.getLoadedSystemIcon(getContextForDisplayLocked(displayId), type,
+                        mUseLargePointerIcons);
+                iconsByType.put(type, icon);
+            }
+            return Objects.requireNonNull(icon);
+        }
+    }
+
+    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
+    private @NonNull Context getContextForDisplayLocked(int displayId) {
+        if (displayId == Display.INVALID_DISPLAY) {
+            // Fallback to using the default context.
+            return mContext;
+        }
+        if (displayId == mContext.getDisplay().getDisplayId()) {
+            return mContext;
+        }
+
+        Context displayContext = mDisplayContexts.get(displayId);
+        if (displayContext == null) {
+            final DisplayManager displayManager = Objects.requireNonNull(
+                    mContext.getSystemService(DisplayManager.class));
+            final Display display = displayManager.getDisplay(displayId);
+            if (display == null) {
+                // Fallback to using the default context.
+                return mContext;
+            }
+
+            displayContext = mContext.createDisplayContext(display);
+            mDisplayContexts.put(displayId, displayContext);
+        }
+        return displayContext;
+    }
+
+    @android.annotation.UiThread
+    private void handleDisplayChanged(int displayId) {
+        synchronized (mLoadedPointerIconsByDisplayAndType) {
+            if (!updateDisplayDensityLocked(displayId)) {
+                return;
+            }
+            // The display density changed, so force all cached pointer icons to be
+            // reloaded for the display.
+            Slog.i(TAG, "Reloading pointer icons due to density change on display: " + displayId);
+            var iconsByType = mLoadedPointerIconsByDisplayAndType.get(displayId);
+            if (iconsByType == null) {
+                return;
+            }
+            iconsByType.clear();
+            mDisplayContexts.remove(displayId);
+        }
+        mNative.reloadPointerIcons();
+    }
+
+    @android.annotation.UiThread
+    private void handleSetUseLargePointerIcons(boolean useLargeIcons) {
+        synchronized (mLoadedPointerIconsByDisplayAndType) {
+            if (mUseLargePointerIcons == useLargeIcons) {
+                return;
+            }
+            mUseLargePointerIcons = useLargeIcons;
+            // Clear all cached icons on all displays.
+            mLoadedPointerIconsByDisplayAndType.clear();
+        }
+        mNative.reloadPointerIcons();
+    }
+
+    // Updates the cached display density for the given displayId, and returns true if
+    // the cached density changed.
+    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
+    private boolean updateDisplayDensityLocked(int displayId) {
+        final DisplayManager displayManager = Objects.requireNonNull(
+                mContext.getSystemService(DisplayManager.class));
+        final Display display = displayManager.getDisplay(displayId);
+        if (display == null) {
+            return false;
+        }
+        DisplayInfo info = new DisplayInfo();
+        display.getDisplayInfo(info);
+        final int oldDensity = mDisplayDensities.get(displayId, 0 /* default */);
+        if (oldDensity == info.logicalDensityDpi) {
+            return false;
+        }
+        mDisplayDensities.put(displayId, info.logicalDensityDpi);
+        return true;
+    }
+}
diff --git a/services/core/java/com/android/server/inputmethod/ClientController.java b/services/core/java/com/android/server/inputmethod/ClientController.java
index 86f4db9..0381a31 100644
--- a/services/core/java/com/android/server/inputmethod/ClientController.java
+++ b/services/core/java/com/android/server/inputmethod/ClientController.java
@@ -33,36 +33,10 @@
 import java.util.function.Consumer;
 
 /**
- * Store and manage {@link InputMethodManagerService} clients. This class was designed to be a
- * singleton in {@link InputMethodManagerService} since it stores information about all clients,
- * still the current client will be defined per display.
- *
- * <p>
- * As part of the re-architecture plan (described in go/imms-rearchitecture-plan), the following
- * fields and methods will be moved out from IMMS and placed here:
- * <ul>
- * <li>mClients (ArrayMap of ClientState indexed by IBinder)</li>
- * </ul>
- * <p>
- * Nested Classes (to move from IMMS):
- * <ul>
- * <li>ClientDeathRecipient</li>
- * <li>ClientState<</li>
- * </ul>
- * <p>
- * Methods to rewrite and/or extract from IMMS and move here:
- * <ul>
- * <li>addClient</li>
- * <li>removeClient</li>
- * <li>verifyClientAndPackageMatch</li>
- * <li>setImeTraceEnabledForAllClients (make it reactive)</li>
- * </ul>
+ * Store and manage {@link InputMethodManagerService} clients.
  */
-// TODO(b/314150112): Update the Javadoc above, by removing the re-architecture steps, once this
-//  class is finalized
 final class ClientController {
 
-    // TODO(b/314150112): Make this field private when breaking the cycle with IMMS.
     @GuardedBy("ImfLock.class")
     private final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
 
diff --git a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
index f1698dd..73f1aad 100644
--- a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
+++ b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
@@ -36,6 +36,7 @@
 import android.os.ResultReceiver;
 import android.util.EventLog;
 import android.util.Slog;
+import android.view.MotionEvent;
 import android.view.inputmethod.ImeTracker;
 import android.view.inputmethod.InputMethod;
 import android.view.inputmethod.InputMethodManager;
@@ -75,7 +76,7 @@
 
     @GuardedBy("ImfLock.class")
     @Override
-    public void performShowIme(IBinder showInputToken, @Nullable ImeTracker.Token statsToken,
+    public void performShowIme(IBinder showInputToken, @NonNull ImeTracker.Token statsToken,
             @InputMethod.ShowFlags int showFlags, ResultReceiver resultReceiver,
             @SoftInputShowHideReason int reason) {
         final IInputMethodInvoker curMethod = mService.getCurMethodLocked();
@@ -88,11 +89,12 @@
             // TODO(b/192412909): Check if we can always call onShowHideSoftInputRequested() or not.
             if (curMethod.showSoftInput(showInputToken, statsToken, showFlags, resultReceiver)) {
                 if (DEBUG_IME_VISIBILITY) {
-                    EventLog.writeEvent(IMF_SHOW_IME, statsToken.getTag(),
-                            Objects.toString(mService.mCurFocusedWindow),
+                    EventLog.writeEvent(IMF_SHOW_IME,
+                            statsToken != null ? statsToken.getTag() : ImeTracker.TOKEN_NONE,
+                            Objects.toString(mService.mImeBindingState.mFocusedWindow),
                             InputMethodDebug.softInputDisplayReasonToString(reason),
                             InputMethodDebug.softInputModeToString(
-                                    mService.mCurFocusedWindowSoftInputMode));
+                                    mService.mImeBindingState.mFocusedWindowSoftInputMode));
                 }
                 mService.onShowHideSoftInputRequested(true /* show */, showInputToken, reason,
                         statsToken);
@@ -102,7 +104,7 @@
 
     @GuardedBy("ImfLock.class")
     @Override
-    public void performHideIme(IBinder hideInputToken, @Nullable ImeTracker.Token statsToken,
+    public void performHideIme(IBinder hideInputToken, @NonNull ImeTracker.Token statsToken,
             ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
         final IInputMethodInvoker curMethod = mService.getCurMethodLocked();
         if (curMethod != null) {
@@ -118,11 +120,12 @@
             // TODO(b/192412909): Check if we can always call onShowHideSoftInputRequested() or not.
             if (curMethod.hideSoftInput(hideInputToken, statsToken, 0, resultReceiver)) {
                 if (DEBUG_IME_VISIBILITY) {
-                    EventLog.writeEvent(IMF_HIDE_IME, statsToken.getTag(),
-                            Objects.toString(mService.mCurFocusedWindow),
+                    EventLog.writeEvent(IMF_HIDE_IME,
+                            statsToken != null ? statsToken.getTag() : ImeTracker.TOKEN_NONE,
+                            Objects.toString(mService.mImeBindingState.mFocusedWindow),
                             InputMethodDebug.softInputDisplayReasonToString(reason),
                             InputMethodDebug.softInputModeToString(
-                                    mService.mCurFocusedWindowSoftInputMode));
+                                    mService.mImeBindingState.mFocusedWindowSoftInputMode));
                 }
                 mService.onShowHideSoftInputRequested(false /* show */, hideInputToken, reason,
                         statsToken);
@@ -132,14 +135,16 @@
 
     @GuardedBy("ImfLock.class")
     @Override
-    public void applyImeVisibility(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
+    public void applyImeVisibility(IBinder windowToken, @NonNull ImeTracker.Token statsToken,
             @ImeVisibilityStateComputer.VisibilityState int state) {
-        applyImeVisibility(windowToken, statsToken, state, -1 /* ignore reason */);
+        applyImeVisibility(windowToken, statsToken, state,
+                SoftInputShowHideReason.NOT_SET /* ignore reason */);
     }
 
     @GuardedBy("ImfLock.class")
     void applyImeVisibility(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
-            @ImeVisibilityStateComputer.VisibilityState int state, int reason) {
+            @ImeVisibilityStateComputer.VisibilityState int state,
+            @SoftInputShowHideReason int reason) {
         switch (state) {
             case STATE_SHOW_IME:
                 ImeTracker.forLogging().onProgress(statsToken,
@@ -164,18 +169,20 @@
                 }
                 break;
             case STATE_HIDE_IME_EXPLICIT:
-                mService.hideCurrentInputLocked(windowToken, statsToken, 0, null, reason);
+                mService.hideCurrentInputLocked(windowToken, statsToken,
+                        0 /* flags */, null /* resultReceiver */, reason);
                 break;
             case STATE_HIDE_IME_NOT_ALWAYS:
                 mService.hideCurrentInputLocked(windowToken, statsToken,
-                        InputMethodManager.HIDE_NOT_ALWAYS, null, reason);
+                        InputMethodManager.HIDE_NOT_ALWAYS, null /* resultReceiver */, reason);
                 break;
             case STATE_SHOW_IME_IMPLICIT:
                 mService.showCurrentInputLocked(windowToken, statsToken,
-                        InputMethodManager.SHOW_IMPLICIT, null, reason);
+                        InputMethodManager.SHOW_IMPLICIT, MotionEvent.TOOL_TYPE_UNKNOWN,
+                        null /* resultReceiver */, reason);
                 break;
             case STATE_SHOW_IME_SNAPSHOT:
-                showImeScreenshot(windowToken, mService.getDisplayIdToShowImeLocked(), null);
+                showImeScreenshot(windowToken, mService.getDisplayIdToShowImeLocked());
                 break;
             case STATE_REMOVE_IME_SNAPSHOT:
                 removeImeScreenshot(mService.getDisplayIdToShowImeLocked());
@@ -187,11 +194,10 @@
 
     @GuardedBy("ImfLock.class")
     @Override
-    public boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId,
-            @Nullable ImeTracker.Token statsToken) {
+    public boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId) {
         if (mImeTargetVisibilityPolicy.showImeScreenshot(imeTarget, displayId)) {
             mService.onShowHideSoftInputRequested(false /* show */, imeTarget,
-                    SHOW_IME_SCREENSHOT_FROM_IMMS, statsToken);
+                    SHOW_IME_SCREENSHOT_FROM_IMMS, null /* statsToken */);
             return true;
         }
         return false;
@@ -201,8 +207,9 @@
     @Override
     public boolean removeImeScreenshot(int displayId) {
         if (mImeTargetVisibilityPolicy.removeImeScreenshot(displayId)) {
-            mService.onShowHideSoftInputRequested(false /* show */, mService.mCurFocusedWindow,
-                    REMOVE_IME_SCREENSHOT_FROM_IMMS, null);
+            mService.onShowHideSoftInputRequested(false /* show */,
+                    mService.mImeBindingState.mFocusedWindow,
+                    REMOVE_IME_SCREENSHOT_FROM_IMMS, null /* statsToken */);
             return true;
         }
         return false;
diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
index 776184f..a380bc1 100644
--- a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
+++ b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
@@ -201,7 +201,7 @@
 
     // TODO(b/192412909): Convert this back to void method
     @AnyThread
-    boolean showSoftInput(IBinder showInputToken, @Nullable ImeTracker.Token statsToken,
+    boolean showSoftInput(IBinder showInputToken, @NonNull ImeTracker.Token statsToken,
             @InputMethod.ShowFlags int flags, ResultReceiver resultReceiver) {
         try {
             mTarget.showSoftInput(showInputToken, statsToken, flags, resultReceiver);
@@ -214,8 +214,8 @@
 
     // TODO(b/192412909): Convert this back to void method
     @AnyThread
-    boolean hideSoftInput(IBinder hideInputToken, @Nullable ImeTracker.Token statsToken, int flags,
-            ResultReceiver resultReceiver) {
+    boolean hideSoftInput(IBinder hideInputToken, @NonNull ImeTracker.Token statsToken,
+            int flags, ResultReceiver resultReceiver) {
         try {
             mTarget.hideSoftInput(hideInputToken, statsToken, flags, resultReceiver);
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/inputmethod/ImeBindingState.java b/services/core/java/com/android/server/inputmethod/ImeBindingState.java
new file mode 100644
index 0000000..4c20c3b
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/ImeBindingState.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.inputmethod;
+
+import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_FOCUSED_WINDOW_NAME;
+import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_FOCUSED_WINDOW_SOFT_INPUT_MODE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED;
+
+import android.annotation.Nullable;
+import android.os.IBinder;
+import android.util.Printer;
+import android.util.proto.ProtoOutputStream;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
+import android.view.inputmethod.EditorInfo;
+
+import com.android.internal.inputmethod.InputMethodDebug;
+import com.android.server.wm.WindowManagerInternal;
+
+/**
+ * Stores information related to one active IME client on one display.
+ */
+final class ImeBindingState {
+
+    /**
+     * The last window token that we confirmed to be focused.  This is always updated upon
+     * reports from the input method client. If the window state is already changed before the
+     * report is handled, this field just keeps the last value.
+     */
+    @Nullable
+    final IBinder mFocusedWindow;
+
+    /**
+     * {@link WindowManager.LayoutParams#softInputMode} of {@link #mFocusedWindow}.
+     *
+     * @see #mFocusedWindow
+     */
+    @SoftInputModeFlags
+    final int mFocusedWindowSoftInputMode;
+
+    /**
+     * The client by which {@link #mFocusedWindow} was reported. This gets updated whenever
+     * an
+     * IME-focusable window gained focus (without necessarily starting an input connection),
+     * while {@link InputMethodManagerService#mClient} only gets updated when we actually start an
+     * input connection.
+     *
+     * @see #mFocusedWindow
+     */
+    @Nullable
+    final ClientState mFocusedWindowClient;
+
+    /**
+     * The editor info by which {@link #mFocusedWindow} was reported. This differs from
+     * {@link InputMethodManagerService#mCurEditorInfo} the same way {@link #mFocusedWindowClient}
+     * differs from {@link InputMethodManagerService#mCurClient}.
+     *
+     * @see #mFocusedWindow
+     */
+    @Nullable
+    final EditorInfo mFocusedWindowEditorInfo;
+
+    void dumpDebug(ProtoOutputStream proto, WindowManagerInternal windowManagerInternal) {
+        proto.write(CUR_FOCUSED_WINDOW_NAME,
+                windowManagerInternal.getWindowName(mFocusedWindow));
+        proto.write(CUR_FOCUSED_WINDOW_SOFT_INPUT_MODE,
+                InputMethodDebug.softInputModeToString(mFocusedWindowSoftInputMode));
+    }
+
+    void dump(String prefix, Printer p) {
+        p.println(prefix + "mFocusedWindow()=" + mFocusedWindow);
+        p.println(prefix + "softInputMode=" + InputMethodDebug.softInputModeToString(
+                mFocusedWindowSoftInputMode));
+        p.println(prefix + "mFocusedWindowClient=" + mFocusedWindowClient);
+    }
+
+    static ImeBindingState newEmptyState() {
+        return new ImeBindingState(
+                /*focusedWindow=*/ null,
+                /*focusedWindowSoftInputMode=*/ SOFT_INPUT_STATE_UNSPECIFIED,
+                /*focusedWindowClient=*/ null,
+                /*focusedWindowEditorInfo=*/ null
+        );
+    }
+
+    ImeBindingState(@Nullable IBinder focusedWindow,
+            @SoftInputModeFlags int focusedWindowSoftInputMode,
+            @Nullable ClientState focusedWindowClient,
+            @Nullable EditorInfo focusedWindowEditorInfo) {
+        mFocusedWindow = focusedWindow;
+        mFocusedWindowSoftInputMode = focusedWindowSoftInputMode;
+        mFocusedWindowClient = focusedWindowClient;
+        mFocusedWindowEditorInfo = focusedWindowEditorInfo;
+    }
+}
diff --git a/services/core/java/com/android/server/inputmethod/ImeTrackerService.java b/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
index d06c31c..85ab773 100644
--- a/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
+++ b/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
@@ -75,34 +75,12 @@
 
     @NonNull
     @Override
-    public ImeTracker.Token onRequestShow(@NonNull String tag, int uid,
+    public ImeTracker.Token onStart(@NonNull String tag, int uid, @ImeTracker.Type int type,
             @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser) {
         final var binder = new Binder();
         final var token = new ImeTracker.Token(binder, tag);
-        final var entry = new History.Entry(tag, uid, ImeTracker.TYPE_SHOW, ImeTracker.STATUS_RUN,
-                origin, reason, fromUser);
-        synchronized (mLock) {
-            mHistory.addEntry(binder, entry);
-
-            // Register a delayed task to handle the case where the new entry times out.
-            mHandler.postDelayed(() -> {
-                synchronized (mLock) {
-                    mHistory.setFinished(token, ImeTracker.STATUS_TIMEOUT,
-                            ImeTracker.PHASE_NOT_SET);
-                }
-            }, TIMEOUT_MS);
-        }
-        return token;
-    }
-
-    @NonNull
-    @Override
-    public ImeTracker.Token onRequestHide(@NonNull String tag, int uid,
-            @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser) {
-        final var binder = new Binder();
-        final var token = new ImeTracker.Token(binder, tag);
-        final var entry = new History.Entry(tag, uid, ImeTracker.TYPE_HIDE, ImeTracker.STATUS_RUN,
-                origin, reason, fromUser);
+        final var entry = new History.Entry(tag, uid, type, ImeTracker.STATUS_RUN, origin, reason,
+                fromUser);
         synchronized (mLock) {
             mHistory.addEntry(binder, entry);
 
@@ -158,7 +136,7 @@
     /**
      * Updates the IME request tracking token with new information available in IMMS.
      *
-     * @param statsToken the token corresponding to the current IME request.
+     * @param statsToken the token tracking the current IME request.
      * @param requestWindowName the name of the window that created the IME request.
      */
     public void onImmsUpdate(@NonNull ImeTracker.Token statsToken,
@@ -223,7 +201,7 @@
          * Sets the live entry corresponding to the tracking token, if it exists, as finished,
          * and uploads the data for metrics.
          *
-         * @param statsToken the token corresponding to the current IME request.
+         * @param statsToken the token tracking the current IME request.
          * @param status the finish status of the IME request.
          * @param phase the phase the IME request finished at, if it exists
          *              (or {@link ImeTracker#PHASE_NOT_SET} otherwise).
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
index 29fa369..9f2b84d 100644
--- a/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
@@ -17,7 +17,6 @@
 package com.android.server.inputmethod;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.os.IBinder;
 import android.os.ResultReceiver;
 import android.view.inputmethod.ImeTracker;
@@ -34,12 +33,12 @@
      * Performs showing IME on top of the given window.
      *
      * @param showInputToken A token that represents the requester to show IME.
-     * @param statsToken     A token that tracks the progress of an IME request.
+     * @param statsToken     The token tracking the current IME request.
      * @param resultReceiver If non-null, this will be called back to the caller when
      *                       it has processed request to tell what it has done.
      * @param reason         The reason for requesting to show IME.
      */
-    default void performShowIme(IBinder showInputToken, @Nullable ImeTracker.Token statsToken,
+    default void performShowIme(IBinder showInputToken, @NonNull ImeTracker.Token statsToken,
             @InputMethod.ShowFlags int showFlags, ResultReceiver resultReceiver,
             @SoftInputShowHideReason int reason) {}
 
@@ -47,12 +46,12 @@
      * Performs hiding IME to the given window
      *
      * @param hideInputToken A token that represents the requester to hide IME.
-     * @param statsToken     A token that tracks the progress of an IME request.
+     * @param statsToken     The token tracking the current IME request.
      * @param resultReceiver If non-null, this will be called back to the caller when
      *                       it has processed request to tell what it has done.
      * @param reason         The reason for requesting to hide IME.
      */
-    default void performHideIme(IBinder hideInputToken, @Nullable ImeTracker.Token statsToken,
+    default void performHideIme(IBinder hideInputToken, @NonNull ImeTracker.Token statsToken,
             ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {}
 
     /**
@@ -60,10 +59,10 @@
      * according to the given visibility state.
      *
      * @param windowToken The token of a window for applying the IME visibility
-     * @param statsToken  A token that tracks the progress of an IME request.
+     * @param statsToken  The token tracking the current IME request.
      * @param state       The new IME visibility state for the applier to handle
      */
-    default void applyImeVisibility(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
+    default void applyImeVisibility(IBinder windowToken, @NonNull ImeTracker.Token statsToken,
             @ImeVisibilityStateComputer.VisibilityState int state) {}
 
     /**
@@ -84,11 +83,9 @@
      *
      * @param windowToken The token of a window to show the IME screenshot.
      * @param displayId The unique id to identify the display
-     * @param statsToken  A token that tracks the progress of an IME request.
      * @return {@code true} if success, {@code false} otherwise.
      */
-    default boolean showImeScreenshot(@NonNull IBinder windowToken, int displayId,
-            @Nullable ImeTracker.Token statsToken) {
+    default boolean showImeScreenshot(@NonNull IBinder windowToken, int displayId) {
         return false;
     }
 
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
index 0dd48ae..cdfde87 100644
--- a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
@@ -212,9 +212,11 @@
                     boolean visibleRequested, boolean removed) {
                 if (mCurVisibleImeInputTarget == imeInputTarget && (!visibleRequested || removed)
                         && mCurVisibleImeLayeringOverlay != null) {
-                    mService.onApplyImeVisibilityFromComputer(imeInputTarget,
-                            new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT,
-                                    SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE));
+                    final int reason = SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE;
+                    final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+                            ImeTracker.ORIGIN_SERVER, reason, false /* fromUser */);
+                    mService.onApplyImeVisibilityFromComputer(imeInputTarget, statsToken,
+                            new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT, reason));
                 }
                 mCurVisibleImeInputTarget = (visibleRequested && !removed) ? imeInputTarget : null;
             }
@@ -224,7 +226,7 @@
     /**
      * Called when {@link InputMethodManagerService} is processing the show IME request.
      *
-     * @param statsToken The token for tracking this show request.
+     * @param statsToken The token tracking the current IME request.
      * @return {@code true} when the show request can proceed.
      */
     boolean onImeShowFlags(@NonNull ImeTracker.Token statsToken,
@@ -250,7 +252,7 @@
     /**
      * Called when {@link InputMethodManagerService} is processing the hide IME request.
      *
-     * @param statsToken The token for tracking this hide request.
+     * @param statsToken The token tracking the current IME request.
      * @return {@code true} when the hide request can proceed.
      */
     boolean canHideIme(@NonNull ImeTracker.Token statsToken,
@@ -546,7 +548,7 @@
             }
         }
         // Fallback to the focused window for some edge cases (e.g. relaunching the activity)
-        return mService.mCurFocusedWindow;
+        return mService.mImeBindingState.mFocusedWindow;
     }
 
     IBinder getWindowTokenFrom(ImeTargetWindowState windowState) {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 76956c88..fee0342 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -28,7 +28,6 @@
 import static android.server.inputmethod.InputMethodManagerServiceProto.BOUND_TO_METHOD;
 import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_ATTRIBUTE;
 import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_CLIENT;
-import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_FOCUSED_WINDOW_NAME;
 import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_FOCUSED_WINDOW_SOFT_INPUT_MODE;
 import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_ID;
 import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_METHOD_ID;
@@ -423,6 +422,11 @@
     private final ClientController mClientController;
 
     /**
+     * Holds the current IME binding state info.
+     */
+    ImeBindingState mImeBindingState;
+
+    /**
      * Set once the system is ready to run third party code.
      */
     boolean mSystemReady;
@@ -482,13 +486,6 @@
     private ClientState mCurClient;
 
     /**
-     * The last window token that we confirmed to be focused.  This is always updated upon reports
-     * from the input method client.  If the window state is already changed before the report is
-     * handled, this field just keeps the last value.
-     */
-    IBinder mCurFocusedWindow;
-
-    /**
      * The last window token that we confirmed that IME started talking to.  This is always updated
      * upon reports from the input method.  If the window state is already changed before the report
      * is handled, this field just keeps the last value.
@@ -496,34 +493,6 @@
     IBinder mLastImeTargetWindow;
 
     /**
-     * {@link LayoutParams#softInputMode} of {@link #mCurFocusedWindow}.
-     *
-     * @see #mCurFocusedWindow
-     */
-    @SoftInputModeFlags
-    int mCurFocusedWindowSoftInputMode;
-
-    /**
-     * The client by which {@link #mCurFocusedWindow} was reported. This gets updated whenever an
-     * IME-focusable window gained focus (without necessarily starting an input connection),
-     * while {@link #mCurClient} only gets updated when we actually start an input connection.
-     *
-     * @see #mCurFocusedWindow
-     */
-    @Nullable
-    ClientState mCurFocusedWindowClient;
-
-    /**
-     * The editor info by which {@link #mCurFocusedWindow} was reported. This differs from
-     * {@link #mCurEditorInfo} the same way {@link #mCurFocusedWindowClient} differs
-     * from {@link #mCurClient}.
-     *
-     * @see #mCurFocusedWindow
-     */
-    @Nullable
-    EditorInfo mCurFocusedWindowEditorInfo;
-
-    /**
      * The {@link IRemoteInputConnection} last provided by the current client.
      */
     IRemoteInputConnection mCurInputConnection;
@@ -578,7 +547,10 @@
         return mBindingController.hasMainConnection();
     }
 
-    /** The token tracking the current IME request or {@code null} otherwise. */
+    /**
+     * The token tracking the current IME show request that is waiting for a connection to an IME,
+     * otherwise {@code null}.
+     */
     @Nullable
     private ImeTracker.Token mCurStatsToken;
 
@@ -1128,11 +1100,11 @@
                     mVisibilityStateComputer.getImePolicy().setA11yRequestNoSoftKeyboard(
                             accessibilitySoftKeyboardSetting);
                     if (mVisibilityStateComputer.getImePolicy().isA11yRequestNoSoftKeyboard()) {
-                        hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */,
-                                0 /* flags */, null /* resultReceiver */,
+                        hideCurrentInputLocked(mImeBindingState.mFocusedWindow, 0 /* flags */,
                                 SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE);
                     } else if (isShowRequestedForCurrentWindow()) {
-                        showCurrentInputImplicitLocked(mCurFocusedWindow,
+                        showCurrentInputLocked(mImeBindingState.mFocusedWindow,
+                                InputMethodManager.SHOW_IMPLICIT,
                                 SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE);
                     }
                 } else if (stylusHandwritingEnabledUri.equals(uri)) {
@@ -1397,43 +1369,57 @@
 
         private void onFinishPackageChangesInternal() {
             synchronized (ImfLock.class) {
-                if (!isChangingPackagesOfCurrentUserLocked()) {
-                    return;
-                }
-                if (!shouldRebuildInputMethodListLocked()) {
-                    return;
+                final int userId = getChangingUserId();
+                final boolean isCurrentUser = (userId == mSettings.getUserId());
+                AdditionalSubtypeMap additionalSubtypeMap;
+                final InputMethodSettings settings;
+                if (isCurrentUser) {
+                    additionalSubtypeMap = mAdditionalSubtypeMap;
+                    settings = mSettings;
+                } else {
+                    additionalSubtypeMap = AdditionalSubtypeUtils.load(userId);
+                    settings = queryInputMethodServicesInternal(mContext, userId,
+                            additionalSubtypeMap, DirectBootAwareness.AUTO);
                 }
 
                 InputMethodInfo curIm = null;
-                String curInputMethodId = mSettings.getSelectedInputMethod();
-                final List<InputMethodInfo> methodList = mSettings.getMethodList();
+                String curInputMethodId = settings.getSelectedInputMethod();
+                final List<InputMethodInfo> methodList = settings.getMethodList();
                 final int numImes = methodList.size();
-                if (curInputMethodId != null) {
-                    for (int i = 0; i < numImes; i++) {
-                        InputMethodInfo imi = methodList.get(i);
-                        final String imiId = imi.getId();
-                        if (imiId.equals(curInputMethodId)) {
-                            curIm = imi;
-                        }
-
-                        int change = isPackageDisappearing(imi.getPackageName());
-                        if (change == PACKAGE_TEMPORARY_CHANGE
-                                || change == PACKAGE_PERMANENT_CHANGE) {
-                            Slog.i(TAG, "Input method uninstalled, disabling: "
-                                    + imi.getComponent());
+                for (int i = 0; i < numImes; i++) {
+                    InputMethodInfo imi = methodList.get(i);
+                    final String imiId = imi.getId();
+                    if (imiId.equals(curInputMethodId)) {
+                        curIm = imi;
+                    }
+                    int change = isPackageDisappearing(imi.getPackageName());
+                    if (change == PACKAGE_TEMPORARY_CHANGE || change == PACKAGE_PERMANENT_CHANGE) {
+                        Slog.i(TAG, "Input method uninstalled, disabling: " + imi.getComponent());
+                        if (isCurrentUser) {
                             setInputMethodEnabledLocked(imi.getId(), false);
-                        } else if (change == PACKAGE_UPDATING) {
-                            Slog.i(TAG,
-                                    "Input method reinstalling, clearing additional subtypes: "
-                                            + imi.getComponent());
-                            mAdditionalSubtypeMap =
-                                    mAdditionalSubtypeMap.cloneWithRemoveOrSelf(imi.getId());
-                            AdditionalSubtypeUtils.save(mAdditionalSubtypeMap,
-                                    mSettings.getMethodMap(), mSettings.getUserId());
+                        } else {
+                            settings.buildAndPutEnabledInputMethodsStrRemovingId(
+                                    new StringBuilder(),
+                                    settings.getEnabledInputMethodsAndSubtypeList(),
+                                    imi.getId());
+                        }
+                    } else if (change == PACKAGE_UPDATING) {
+                        Slog.i(TAG, "Input method reinstalling, clearing additional subtypes: "
+                                + imi.getComponent());
+                        additionalSubtypeMap =
+                                additionalSubtypeMap.cloneWithRemoveOrSelf(imi.getId());
+                        AdditionalSubtypeUtils.save(additionalSubtypeMap,
+                                settings.getMethodMap(), userId);
+                        if (isCurrentUser) {
+                            mAdditionalSubtypeMap = additionalSubtypeMap;
                         }
                     }
                 }
 
+                if (!isCurrentUser || !shouldRebuildInputMethodListLocked()) {
+                    return;
+                }
+
                 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
 
                 boolean changed = false;
@@ -1443,7 +1429,7 @@
                     if (change == PACKAGE_TEMPORARY_CHANGE
                             || change == PACKAGE_PERMANENT_CHANGE) {
                         final PackageManager userAwarePackageManager =
-                                getPackageManagerForUser(mContext, mSettings.getUserId());
+                                getPackageManagerForUser(mContext, userId);
                         ServiceInfo si = null;
                         try {
                             si = userAwarePackageManager.getServiceInfo(curIm.getComponent(),
@@ -1613,8 +1599,8 @@
         }
         // Hide soft input before user switch task since switch task may block main handler a while
         // and delayed the hideCurrentInputLocked().
-        hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
-                null /* resultReceiver */, SoftInputShowHideReason.HIDE_SWITCH_USER);
+        hideCurrentInputLocked(mImeBindingState.mFocusedWindow, 0 /* flags */,
+                SoftInputShowHideReason.HIDE_SWITCH_USER);
         final UserSwitchHandlerTask task = new UserSwitchHandlerTask(this, userId,
                 clientToBeReset);
         mUserSwitchHandlerTask = task;
@@ -1688,6 +1674,7 @@
         mClientController = new ClientController(mPackageManagerInternal);
         synchronized (ImfLock.class) {
             mClientController.addClientControllerCallback(c -> onClientRemoved(c));
+            mImeBindingState = ImeBindingState.newEmptyState();
         }
 
         mPreventImeStartupUnlessTextEditor = mRes.getBoolean(
@@ -2193,7 +2180,7 @@
         }
     }
 
-    // TODO(b/314150112): Move this method to InputMethodBindingController
+    // TODO(b/325515685): Move this method to InputMethodBindingController
     /**
      * Hide the IME if the removed user is the current user.
      */
@@ -2202,8 +2189,8 @@
         clearClientSessionLocked(client);
         clearClientSessionForAccessibilityLocked(client);
         if (mCurClient == client) {
-            hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
-                    null /* resultReceiver */, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
+            hideCurrentInputLocked(mImeBindingState.mFocusedWindow, 0 /* flags */,
+                    SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
             if (mBoundToMethod) {
                 mBoundToMethod = false;
                 IInputMethodInvoker curMethod = getCurMethodLocked();
@@ -2216,9 +2203,8 @@
             }
             mBoundToAccessibility = false;
             mCurClient = null;
-            if (mCurFocusedWindowClient == client) {
-                mCurFocusedWindowClient = null;
-                mCurFocusedWindowEditorInfo = null;
+            if (mImeBindingState.mFocusedWindowClient == client) {
+                mImeBindingState = ImeBindingState.newEmptyState();
             }
         }
     }
@@ -2267,7 +2253,7 @@
     @GuardedBy("ImfLock.class")
     void onUnbindCurrentMethodByReset() {
         final ImeTargetWindowState winState = mVisibilityStateComputer.getWindowStateOrNull(
-                mCurFocusedWindow);
+                mImeBindingState.mFocusedWindow);
         if (winState != null && !winState.isRequestedImeVisible()
                 && !mVisibilityStateComputer.isInputShown()) {
             // Normally, the focus window will apply the IME visibility state to
@@ -2277,7 +2263,9 @@
             // service, that wouldn't make the attached IME token validity check in time)
             // As a result, we have to notify WM to apply IME visibility before clearing the
             // binding states in the first place.
-            mVisibilityApplier.applyImeVisibility(mCurFocusedWindow, mCurStatsToken,
+            final var statsToken = createStatsTokenForFocusedClient(false /* show */,
+                    SoftInputShowHideReason.UNBIND_CURRENT_METHOD);
+            mVisibilityApplier.applyImeVisibility(mImeBindingState.mFocusedWindow, statsToken,
                     STATE_HIDE_IME);
         }
     }
@@ -2311,7 +2299,7 @@
     @GuardedBy("ImfLock.class")
     private boolean isShowRequestedForCurrentWindow() {
         final ImeTargetWindowState state = mVisibilityStateComputer.getWindowStateOrNull(
-                mCurFocusedWindow);
+                mImeBindingState.mFocusedWindow);
         return state != null && state.isRequestedImeVisible();
     }
 
@@ -2329,10 +2317,9 @@
                 getCurTokenLocked(),
                 mCurTokenDisplayId, getCurIdLocked(), startInputReason, restarting,
                 UserHandle.getUserId(mCurClient.mUid),
-                mCurClient.mSelfReportedDisplayId,
-                mCurFocusedWindow, mCurEditorInfo, mCurFocusedWindowSoftInputMode,
-                getSequenceNumberLocked());
-        mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow);
+                mCurClient.mSelfReportedDisplayId, mImeBindingState.mFocusedWindow, mCurEditorInfo,
+                mImeBindingState.mFocusedWindowSoftInputMode, getSequenceNumberLocked());
+        mImeTargetWindowMap.put(startInputToken, mImeBindingState.mFocusedWindow);
         mStartInputHistory.addEntry(info);
 
         // Seems that PackageManagerInternal#grantImplicitAccess() doesn't handle cross-user
@@ -2355,10 +2342,12 @@
         if (isShowRequestedForCurrentWindow()) {
             if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
             // Re-use current statsToken, if it exists.
-            final ImeTracker.Token statsToken = mCurStatsToken;
+            final var statsToken = mCurStatsToken != null ? mCurStatsToken
+                    : createStatsTokenForFocusedClient(true /* show */,
+                            SoftInputShowHideReason.ATTACH_NEW_INPUT);
             mCurStatsToken = null;
-            showCurrentInputLocked(mCurFocusedWindow, statsToken,
-                    mVisibilityStateComputer.getShowFlags(),
+            showCurrentInputLocked(mImeBindingState.mFocusedWindow, statsToken,
+                    mVisibilityStateComputer.getShowFlags(), MotionEvent.TOOL_TYPE_UNKNOWN,
                     null /* resultReceiver */, SoftInputShowHideReason.ATTACH_NEW_INPUT);
         }
 
@@ -2431,7 +2420,7 @@
         // Compute the final shown display ID with validated cs.selfReportedDisplayId for this
         // session & other conditions.
         ImeTargetWindowState winState = mVisibilityStateComputer.getWindowStateOrNull(
-                mCurFocusedWindow);
+                mImeBindingState.mFocusedWindow);
         if (winState == null) {
             return InputBindResult.NOT_IME_TARGET_WINDOW;
         }
@@ -2450,8 +2439,7 @@
         }
 
         if (mVisibilityStateComputer.getImePolicy().isImeHiddenByDisplayPolicy()) {
-            hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
-                    null /* resultReceiver */,
+            hideCurrentInputLocked(mImeBindingState.mFocusedWindow, 0 /* flags */,
                     SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE);
             return InputBindResult.NO_IME;
         }
@@ -3371,8 +3359,8 @@
 
     @Override
     public boolean showSoftInput(IInputMethodClient client, IBinder windowToken,
-            @Nullable ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
-            int lastClickTooType, ResultReceiver resultReceiver,
+            @NonNull ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
+            int lastClickToolType, ResultReceiver resultReceiver,
             @SoftInputShowHideReason int reason) {
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showSoftInput");
         int uid = Binder.getCallingUid();
@@ -3388,7 +3376,7 @@
             final long ident = Binder.clearCallingIdentity();
             try {
                 if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
-                return showCurrentInputLocked(windowToken, statsToken, flags, lastClickTooType,
+                return showCurrentInputLocked(windowToken, statsToken, flags, lastClickToolType,
                         resultReceiver, reason);
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -3620,7 +3608,8 @@
         Binder.withCleanCallingIdentity(() -> {
             Objects.requireNonNull(windowToken, "windowToken must not be null");
             synchronized (ImfLock.class) {
-                if (mCurFocusedWindow != windowToken || mCurPerceptible == perceptible) {
+                if (mImeBindingState.mFocusedWindow != windowToken
+                        || mCurPerceptible == perceptible) {
                     return;
                 }
                 mCurPerceptible = perceptible;
@@ -3630,24 +3619,18 @@
     }
 
     @GuardedBy("ImfLock.class")
-    boolean showCurrentInputLocked(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
-            @InputMethodManager.ShowFlags int flags, ResultReceiver resultReceiver,
-            @SoftInputShowHideReason int reason) {
+    private boolean showCurrentInputLocked(IBinder windowToken,
+            @InputMethodManager.ShowFlags int flags, @SoftInputShowHideReason int reason) {
+        final var statsToken = createStatsTokenForFocusedClient(true /* show */, reason);
         return showCurrentInputLocked(windowToken, statsToken, flags,
-                MotionEvent.TOOL_TYPE_UNKNOWN, resultReceiver, reason);
+                MotionEvent.TOOL_TYPE_UNKNOWN, null /* resultReceiver */, reason);
     }
 
     @GuardedBy("ImfLock.class")
-    private boolean showCurrentInputLocked(IBinder windowToken,
-            @Nullable ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
-            int lastClickToolType, ResultReceiver resultReceiver,
+    boolean showCurrentInputLocked(IBinder windowToken,
+            @NonNull ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
+            int lastClickToolType, @Nullable ResultReceiver resultReceiver,
             @SoftInputShowHideReason int reason) {
-        // Create statsToken is none exists.
-        if (statsToken == null) {
-            statsToken = createStatsTokenForFocusedClient(true /* show */,
-                    ImeTracker.ORIGIN_SERVER_START_INPUT, reason, false /* fromUser */);
-        }
-
         if (!mVisibilityStateComputer.onImeShowFlags(statsToken, flags)) {
             return false;
         }
@@ -3685,7 +3668,7 @@
 
     @Override
     public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken,
-            @Nullable ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
+            @NonNull ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
             ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
         int uid = Binder.getCallingUid();
         ImeTracing.getInstance().triggerManagerServiceDump(
@@ -3714,17 +3697,29 @@
         }
     }
 
-    @GuardedBy("ImfLock.class")
-    boolean hideCurrentInputLocked(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
-            @InputMethodManager.HideFlags int flags, ResultReceiver resultReceiver,
-            @SoftInputShowHideReason int reason) {
-        // Create statsToken is none exists.
-        if (statsToken == null) {
-            final boolean fromUser = reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY;
-            statsToken = createStatsTokenForFocusedClient(false /* show */,
-                    ImeTracker.ORIGIN_SERVER_HIDE_INPUT, reason, fromUser);
-        }
+    @Override
+    @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD)
+    public void hideSoftInputFromServerForTest() {
+        super.hideSoftInputFromServerForTest_enforcePermission();
 
+        synchronized (ImfLock.class) {
+            hideCurrentInputLocked(mImeBindingState.mFocusedWindow, 0 /* flags */,
+                    SoftInputShowHideReason.HIDE_SOFT_INPUT);
+        }
+    }
+
+    @GuardedBy("ImfLock.class")
+    private boolean hideCurrentInputLocked(IBinder windowToken,
+            @InputMethodManager.HideFlags int flags, @SoftInputShowHideReason int reason) {
+        final var statsToken = createStatsTokenForFocusedClient(false /* show */, reason);
+        return hideCurrentInputLocked(windowToken, statsToken, flags, null /* resultReceiver */,
+                reason);
+    }
+
+    @GuardedBy("ImfLock.class")
+    boolean hideCurrentInputLocked(IBinder windowToken, @NonNull ImeTracker.Token statsToken,
+            @InputMethodManager.HideFlags int flags, @Nullable ResultReceiver resultReceiver,
+            @SoftInputShowHideReason int reason) {
         if (!mVisibilityStateComputer.canHideIme(statsToken, flags)) {
             return false;
         }
@@ -3883,7 +3878,8 @@
                     final boolean shouldClearFlag =
                             mImePlatformCompatUtils.shouldClearShowForcedFlag(cs.mUid);
                     final boolean showForced = mVisibilityStateComputer.mShowForced;
-                    if (mCurFocusedWindow != windowToken && showForced && shouldClearFlag) {
+                    if (mImeBindingState.mFocusedWindow != windowToken
+                            && showForced && shouldClearFlag) {
                         mVisibilityStateComputer.mShowForced = false;
                     }
 
@@ -3901,9 +3897,7 @@
                         Slog.w(TAG, "If you need to impersonate a foreground user/profile from"
                                 + " a background user, use EditorInfo.targetInputMethodUser with"
                                 + " INTERACT_ACROSS_USERS_FULL permission.");
-                        hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */,
-                                0 /* flags */,
-                                null /* resultReceiver */,
+                        hideCurrentInputLocked(mImeBindingState.mFocusedWindow, 0 /* flags */,
                                 SoftInputShowHideReason.HIDE_INVALID_USER);
                         return InputBindResult.INVALID_USER;
                     }
@@ -3964,7 +3958,7 @@
                     + " cs=" + cs);
         }
 
-        final boolean sameWindowFocused = mCurFocusedWindow == windowToken;
+        final boolean sameWindowFocused = mImeBindingState.mFocusedWindow == windowToken;
         final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
         final boolean startInputByWinGainedFocus =
                 (startInputFlags & StartInputFlags.WINDOW_GAINED_FOCUS) != 0;
@@ -3995,10 +3989,7 @@
                     null, null, null, null, -1, false);
         }
 
-        mCurFocusedWindow = windowToken;
-        mCurFocusedWindowSoftInputMode = softInputMode;
-        mCurFocusedWindowClient = cs;
-        mCurFocusedWindowEditorInfo = editorInfo;
+        mImeBindingState = new ImeBindingState(windowToken, softInputMode, cs, editorInfo);
         mCurPerceptible = true;
 
         // We want to start input before showing the IME, but after closing
@@ -4011,11 +4002,14 @@
         final ImeVisibilityResult imeVisRes = mVisibilityStateComputer.computeState(windowState,
                 isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion, startInputFlags));
         if (imeVisRes != null) {
+            boolean isShow = false;
             switch (imeVisRes.getReason()) {
                 case SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY:
                 case SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV:
                 case SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV:
                 case SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE:
+                    isShow = true;
+
                     if (editorInfo != null) {
                         res = startInputUncheckedLocked(cs, inputContext,
                                 remoteAccessibilityInputConnection, editorInfo, startInputFlags,
@@ -4025,10 +4019,9 @@
                     }
                     break;
             }
-
-            mVisibilityApplier.applyImeVisibility(mCurFocusedWindow, null /* statsToken */,
+            final var statsToken = createStatsTokenForFocusedClient(isShow, imeVisRes.getReason());
+            mVisibilityApplier.applyImeVisibility(mImeBindingState.mFocusedWindow, statsToken,
                     imeVisRes.getState(), imeVisRes.getReason());
-
             if (imeVisRes.getReason() == SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW) {
                 // If focused display changed, we should unbind current method
                 // to make app window in previous display relayout after Ime
@@ -4054,13 +4047,6 @@
     }
 
     @GuardedBy("ImfLock.class")
-    private void showCurrentInputImplicitLocked(@NonNull IBinder windowToken,
-            @SoftInputShowHideReason int reason) {
-        showCurrentInputLocked(windowToken, null /* statsToken */, InputMethodManager.SHOW_IMPLICIT,
-                null /* resultReceiver */, reason);
-    }
-
-    @GuardedBy("ImfLock.class")
     private boolean canInteractWithImeLocked(int uid, IInputMethodClient client, String methodName,
             @Nullable ImeTracker.Token statsToken) {
         if (mCurClient == null || client == null
@@ -4074,7 +4060,7 @@
                 throw new IllegalArgumentException("unknown client " + client.asBinder());
             }
             ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_CLIENT_KNOWN);
-            if (!isImeClientFocused(mCurFocusedWindow, cs)) {
+            if (!isImeClientFocused(mImeBindingState.mFocusedWindow, cs)) {
                 Slog.w(TAG, String.format("Ignoring %s of uid %d : %s", methodName, uid, client));
                 return false;
             }
@@ -4086,8 +4072,8 @@
     @GuardedBy("ImfLock.class")
     private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
         final int uid = Binder.getCallingUid();
-        if (mCurFocusedWindowClient != null && client != null
-                && mCurFocusedWindowClient.mClient.asBinder() == client.asBinder()) {
+        if (mImeBindingState.mFocusedWindowClient != null && client != null
+                && mImeBindingState.mFocusedWindowClient.mClient.asBinder() == client.asBinder()) {
             return true;
         }
         if (mSettings.getUserId() != UserHandle.getUserId(uid)) {
@@ -4710,12 +4696,11 @@
             proto.write(CUR_METHOD_ID, getSelectedMethodIdLocked());
             proto.write(CUR_SEQ, getSequenceNumberLocked());
             proto.write(CUR_CLIENT, Objects.toString(mCurClient));
-            proto.write(CUR_FOCUSED_WINDOW_NAME,
-                    mWindowManagerInternal.getWindowName(mCurFocusedWindow));
+            mImeBindingState.dumpDebug(proto, mWindowManagerInternal);
             proto.write(LAST_IME_TARGET_WINDOW_NAME,
                     mWindowManagerInternal.getWindowName(mLastImeTargetWindow));
-            proto.write(CUR_FOCUSED_WINDOW_SOFT_INPUT_MODE,
-                    InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode));
+            proto.write(CUR_FOCUSED_WINDOW_SOFT_INPUT_MODE, InputMethodDebug.softInputModeToString(
+                    mImeBindingState.mFocusedWindowSoftInputMode));
             if (mCurEditorInfo != null) {
                 mCurEditorInfo.dumpDebug(proto, CUR_ATTRIBUTE);
             }
@@ -4762,15 +4747,17 @@
 
     @BinderThread
     private void applyImeVisibility(IBinder token, IBinder windowToken, boolean setVisible,
-            @Nullable ImeTracker.Token statsToken) {
+            @NonNull ImeTracker.Token statsToken) {
         try {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.applyImeVisibility");
             synchronized (ImfLock.class) {
                 if (!calledWithValidTokenLocked(token)) {
                     ImeTracker.forLogging().onFailed(statsToken,
-                            ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
+                            ImeTracker.PHASE_SERVER_CURRENT_ACTIVE_IME);
                     return;
                 }
+                ImeTracker.forLogging().onProgress(statsToken,
+                        ImeTracker.PHASE_SERVER_CURRENT_ACTIVE_IME);
                 final IBinder requestToken = mVisibilityStateComputer.getWindowTokenFrom(
                         windowToken);
                 mVisibilityApplier.applyImeVisibility(requestToken, statsToken,
@@ -4835,12 +4822,12 @@
         final IBinder requestToken = mVisibilityStateComputer.getWindowTokenFrom(requestImeToken);
         final WindowManagerInternal.ImeTargetInfo info =
                 mWindowManagerInternal.onToggleImeRequested(
-                        show, mCurFocusedWindow, requestToken, mCurTokenDisplayId);
+                        show, mImeBindingState.mFocusedWindow, requestToken, mCurTokenDisplayId);
         mSoftInputShowHideHistory.addEntry(new SoftInputShowHideHistory.Entry(
-                mCurFocusedWindowClient, mCurFocusedWindowEditorInfo, info.focusedWindowName,
-                mCurFocusedWindowSoftInputMode, reason, mInFullscreenMode,
-                info.requestWindowName, info.imeControlTargetName, info.imeLayerTargetName,
-                info.imeSurfaceParentName));
+                mImeBindingState.mFocusedWindowClient, mImeBindingState.mFocusedWindowEditorInfo,
+                info.focusedWindowName, mImeBindingState.mFocusedWindowSoftInputMode, reason,
+                mInFullscreenMode, info.requestWindowName, info.imeControlTargetName,
+                info.imeLayerTargetName, info.imeSurfaceParentName));
 
         if (statsToken != null) {
             mImeTrackerService.onImmsUpdate(statsToken, info.requestWindowName);
@@ -4848,17 +4835,21 @@
     }
 
     @BinderThread
-    private void hideMySoftInput(@NonNull IBinder token, @InputMethodManager.HideFlags int flags,
-            @SoftInputShowHideReason int reason) {
+    private void hideMySoftInput(@NonNull IBinder token, @NonNull ImeTracker.Token statsToken,
+            @InputMethodManager.HideFlags int flags, @SoftInputShowHideReason int reason) {
         try {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.hideMySoftInput");
             synchronized (ImfLock.class) {
                 if (!calledWithValidTokenLocked(token)) {
+                    ImeTracker.forLogging().onFailed(statsToken,
+                            ImeTracker.PHASE_SERVER_CURRENT_ACTIVE_IME);
                     return;
                 }
+                ImeTracker.forLogging().onProgress(statsToken,
+                        ImeTracker.PHASE_SERVER_CURRENT_ACTIVE_IME);
                 final long ident = Binder.clearCallingIdentity();
                 try {
-                    hideCurrentInputLocked(mLastImeTargetWindow, null /* statsToken */, flags,
+                    hideCurrentInputLocked(mLastImeTargetWindow, statsToken, flags,
                             null /* resultReceiver */, reason);
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -4870,18 +4861,22 @@
     }
 
     @BinderThread
-    private void showMySoftInput(@NonNull IBinder token, @InputMethodManager.ShowFlags int flags) {
+    private void showMySoftInput(@NonNull IBinder token, @NonNull ImeTracker.Token statsToken,
+            @InputMethodManager.ShowFlags int flags, @SoftInputShowHideReason int reason) {
         try {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showMySoftInput");
             synchronized (ImfLock.class) {
                 if (!calledWithValidTokenLocked(token)) {
+                    ImeTracker.forLogging().onFailed(statsToken,
+                            ImeTracker.PHASE_SERVER_CURRENT_ACTIVE_IME);
                     return;
                 }
+                ImeTracker.forLogging().onProgress(statsToken,
+                        ImeTracker.PHASE_SERVER_CURRENT_ACTIVE_IME);
                 final long ident = Binder.clearCallingIdentity();
                 try {
-                    showCurrentInputLocked(mLastImeTargetWindow, null /* statsToken */, flags,
-                            null /* resultReceiver */,
-                            SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME);
+                    showCurrentInputLocked(mLastImeTargetWindow, statsToken, flags,
+                            MotionEvent.TOOL_TYPE_UNKNOWN, null /* resultReceiver */, reason);
                 } finally {
                     Binder.restoreCallingIdentity(ident);
                 }
@@ -4898,10 +4893,10 @@
         }
     }
 
-    void onApplyImeVisibilityFromComputer(IBinder windowToken,
+    void onApplyImeVisibilityFromComputer(IBinder windowToken, @NonNull ImeTracker.Token statsToken,
             @NonNull ImeVisibilityResult result) {
         synchronized (ImfLock.class) {
-            mVisibilityApplier.applyImeVisibility(windowToken, null, result.getState(),
+            mVisibilityApplier.applyImeVisibility(windowToken, statsToken, result.getState(),
                     result.getReason());
         }
     }
@@ -5002,10 +4997,8 @@
 
             case MSG_HIDE_ALL_INPUT_METHODS:
                 synchronized (ImfLock.class) {
-                    final @SoftInputShowHideReason int reason = (int) msg.obj;
-                    hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
-                            null /* resultReceiver */, reason);
-
+                    @SoftInputShowHideReason final int reason = (int) msg.obj;
+                    hideCurrentInputLocked(mImeBindingState.mFocusedWindow, 0 /* flags */, reason);
                 }
                 return true;
             case MSG_REMOVE_IME_SURFACE: {
@@ -5024,7 +5017,7 @@
                 IBinder windowToken = (IBinder) msg.obj;
                 synchronized (ImfLock.class) {
                     try {
-                        if (windowToken == mCurFocusedWindow
+                        if (windowToken == mImeBindingState.mFocusedWindow
                                 && mEnabledSession != null && mEnabledSession.mSession != null) {
                             mEnabledSession.mSession.removeImeSurface();
                         }
@@ -5099,7 +5092,7 @@
             case MSG_START_HANDWRITING:
                 synchronized (ImfLock.class) {
                     IInputMethodInvoker curMethod = getCurMethodLocked();
-                    if (curMethod == null || mCurFocusedWindow == null) {
+                    if (curMethod == null || mImeBindingState.mFocusedWindow == null) {
                         return true;
                     }
                     final HandwritingModeController.HandwritingSession session =
@@ -5107,7 +5100,7 @@
                                     msg.arg1 /*requestId*/,
                                     msg.arg2 /*pid*/,
                                     mBindingController.getCurMethodUid(),
-                                    mCurFocusedWindow);
+                                    mImeBindingState.mFocusedWindow);
                     if (session == null) {
                         Slog.e(TAG,
                                 "Failed to start handwriting session for requestId: " + msg.arg1);
@@ -5160,10 +5153,11 @@
                 // Handle IME visibility when interactive changed before finishing the input to
                 // ensure we preserve the last state as possible.
                 final ImeVisibilityResult imeVisRes = mVisibilityStateComputer.onInteractiveChanged(
-                        mCurFocusedWindow, interactive);
+                        mImeBindingState.mFocusedWindow, interactive);
                 if (imeVisRes != null) {
-                    mVisibilityApplier.applyImeVisibility(mCurFocusedWindow, null,
-                            imeVisRes.getState(), imeVisRes.getReason());
+                    // Pass in a null statsToken as the IME snapshot is not tracked by ImeTracker.
+                    mVisibilityApplier.applyImeVisibility(mImeBindingState.mFocusedWindow,
+                            null /* statsToken */, imeVisRes.getState(), imeVisRes.getReason());
                 }
                 // Eligible IME processes use new "setInteractive" protocol.
                 mCurClient.mClient.setInteractive(mIsInteractive, mInFullscreenMode);
@@ -5853,7 +5847,7 @@
         @Override
         public void reportImeControl(@Nullable IBinder windowToken) {
             synchronized (ImfLock.class) {
-                if (mCurFocusedWindow != windowToken) {
+                if (mImeBindingState.mFocusedWindow != windowToken) {
                     // mCurPerceptible was set by the focused window, but it is no longer in
                     // control, so we reset mCurPerceptible.
                     mCurPerceptible = true;
@@ -5867,7 +5861,7 @@
                 // Hide the IME method menu only when the IME surface parent is changed by the
                 // input target changed, in case seeing the dialog dismiss flickering during
                 // the next focused window starting the input connection.
-                if (mLastImeTargetWindow != mCurFocusedWindow) {
+                if (mLastImeTargetWindow != mImeBindingState.mFocusedWindow) {
                     mMenuController.hideInputMethodMenuLocked();
                 }
             }
@@ -6161,11 +6155,7 @@
             client = mCurClient;
             p.println("  mCurClient=" + client + " mCurSeq=" + getSequenceNumberLocked());
             p.println("  mCurPerceptible=" + mCurPerceptible);
-            p.println("  mCurFocusedWindow=" + mCurFocusedWindow
-                    + " softInputMode="
-                    + InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode)
-                    + " client=" + mCurFocusedWindowClient);
-            focusedWindowClient = mCurFocusedWindowClient;
+            mImeBindingState.dump("  ", p);
             p.println("  mCurId=" + getCurIdLocked() + " mHaveConnection=" + hasConnectionLocked()
                     + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound="
                     + mBindingController.isVisibleBound());
@@ -6216,7 +6206,8 @@
             p.println("No input method client.");
         }
 
-        if (focusedWindowClient != null && client != focusedWindowClient) {
+        if (mImeBindingState.mFocusedWindowClient != null
+                && client != mImeBindingState.mFocusedWindowClient) {
             p.println(" ");
             p.println("Warning: Current input method client doesn't match the last focused. "
                     + "window.");
@@ -6224,7 +6215,8 @@
             p.println(" ");
             pw.flush();
             try {
-                TransferPipe.dumpAsync(focusedWindowClient.mClient.asBinder(), fd, args);
+                TransferPipe.dumpAsync(
+                        mImeBindingState.mFocusedWindowClient.mClient.asBinder(), fd, args);
             } catch (IOException | RemoteException e) {
                 p.println("Failed to dump input method client in focused window: " + e);
             }
@@ -6670,8 +6662,7 @@
                     final String nextIme;
                     final List<InputMethodInfo> nextEnabledImes;
                     if (userId == mSettings.getUserId()) {
-                        hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */,
-                                0 /* flags */, null /* resultReceiver */,
+                        hideCurrentInputLocked(mImeBindingState.mFocusedWindow, 0 /* flags */,
                                 SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND);
                         mBindingController.unbindCurrentMethod();
 
@@ -6800,27 +6791,21 @@
      * Creates an IME request tracking token for the current focused client.
      *
      * @param show whether this is a show or a hide request.
-     * @param origin the origin of the IME request.
      * @param reason the reason why the IME request was created.
-     * @param fromUser whether this request was created directly from user interaction.
      */
     @NonNull
     private ImeTracker.Token createStatsTokenForFocusedClient(boolean show,
-            @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser) {
-        final int uid = mCurFocusedWindowClient != null
-                ? mCurFocusedWindowClient.mUid
+            @SoftInputShowHideReason int reason) {
+        final int uid = mImeBindingState.mFocusedWindowClient != null
+                ? mImeBindingState.mFocusedWindowClient.mUid
                 : -1;
-        final var packageName = mCurFocusedWindowEditorInfo != null
-                ? mCurFocusedWindowEditorInfo.packageName
+        final var packageName = mImeBindingState.mFocusedWindowEditorInfo != null
+                ? mImeBindingState.mFocusedWindowEditorInfo.packageName
                 : "uid(" + uid + ")";
 
-        if (show) {
-            return ImeTracker.forLogging()
-                    .onRequestShow(packageName, uid, origin, reason, fromUser);
-        } else {
-            return ImeTracker.forLogging()
-                    .onRequestHide(packageName, uid, origin, reason, fromUser);
-        }
+        return ImeTracker.forLogging().onStart(packageName, uid,
+                show ? ImeTracker.TYPE_SHOW : ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_SERVER,
+                reason, false /* fromUser */);
     }
 
     private static final class InputMethodPrivilegedOperationsImpl
@@ -6895,12 +6880,13 @@
 
         @BinderThread
         @Override
-        public void hideMySoftInput(@InputMethodManager.HideFlags int flags,
-                @SoftInputShowHideReason int reason, AndroidFuture future /* T=Void */) {
+        public void hideMySoftInput(@NonNull ImeTracker.Token statsToken,
+                @InputMethodManager.HideFlags int flags, @SoftInputShowHideReason int reason,
+                AndroidFuture future /* T=Void */) {
             @SuppressWarnings("unchecked")
             final AndroidFuture<Void> typedFuture = future;
             try {
-                mImms.hideMySoftInput(mToken, flags, reason);
+                mImms.hideMySoftInput(mToken, statsToken, flags, reason);
                 typedFuture.complete(null);
             } catch (Throwable e) {
                 typedFuture.completeExceptionally(e);
@@ -6909,12 +6895,13 @@
 
         @BinderThread
         @Override
-        public void showMySoftInput(@InputMethodManager.ShowFlags int flags,
+        public void showMySoftInput(@NonNull ImeTracker.Token statsToken,
+                @InputMethodManager.ShowFlags int flags, @SoftInputShowHideReason int reason,
                 AndroidFuture future /* T=Void */) {
             @SuppressWarnings("unchecked")
             final AndroidFuture<Void> typedFuture = future;
             try {
-                mImms.showMySoftInput(mToken, flags);
+                mImms.showMySoftInput(mToken, statsToken, flags, reason);
                 typedFuture.complete(null);
             } catch (Throwable e) {
                 typedFuture.completeExceptionally(e);
@@ -6973,7 +6960,7 @@
         @BinderThread
         @Override
         public void applyImeVisibilityAsync(IBinder windowToken, boolean setVisible,
-                @Nullable ImeTracker.Token statsToken) {
+                @NonNull ImeTracker.Token statsToken) {
             mImms.applyImeVisibility(mToken, windowToken, setVisible, statsToken);
         }
 
diff --git a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
index 62d4455..9caf5cf 100644
--- a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
+++ b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
@@ -72,6 +72,7 @@
 import com.android.internal.view.IInputMethodManager;
 
 import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
@@ -183,6 +184,13 @@
         return true;
     }
 
+    @Override
+    @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD)
+    public void hideSoftInputFromServerForTest() throws RemoteException {
+        super.hideSoftInputFromServerForTest_enforcePermission();
+        mInner.hideSoftInputFromServerForTest();
+    }
+
     @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
     @Override
     public void startInputOrWindowGainedFocusAsync(
@@ -404,6 +412,13 @@
                 in, out, err, args, callback, resultReceiver);
     }
 
+    @Override
+    protected void dump(@NonNull FileDescriptor fd,
+            @NonNull PrintWriter fout,
+            @Nullable String[] args) {
+        ((InputMethodManagerService) mInner).dump(fd, fout, args);
+    }
+
     private void sendOnStartInputResult(
             IInputMethodClient client, InputBindResult res, int startInputSeq) {
         InputMethodManagerService service = (InputMethodManagerService) mInner;
diff --git a/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java b/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
index 2522f7b..470cc04 100644
--- a/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
@@ -109,20 +109,15 @@
 
         synchronized (mLock) {
             mDeviceIdleHelper.addListener(this);
-            mDeviceIdle = mDeviceIdleHelper.isDeviceIdle();
-            mDeviceStationaryHelper.addListener(this);
-            mDeviceStationary = false;
-            mDeviceStationaryRealtimeMs = Long.MIN_VALUE;
-
-            onThrottlingChangedLocked(false);
+            onDeviceIdleChanged(mDeviceIdleHelper.isDeviceIdle());
         }
     }
 
     @Override
     protected void onStop() {
         synchronized (mLock) {
-            mDeviceStationaryHelper.removeListener(this);
             mDeviceIdleHelper.removeListener(this);
+            onDeviceIdleChanged(false);
 
             mIncomingRequest = ProviderRequest.EMPTY_REQUEST;
             mOutgoingRequest = ProviderRequest.EMPTY_REQUEST;
@@ -155,13 +150,26 @@
             }
 
             mDeviceIdle = deviceIdle;
-            onThrottlingChangedLocked(false);
+            if (deviceIdle) {
+                // device stationary helper will deliver an immediate listener update
+                mDeviceStationaryHelper.addListener(this);
+            } else {
+                mDeviceStationaryHelper.removeListener(this);
+                mDeviceStationary = false;
+                mDeviceStationaryRealtimeMs = Long.MIN_VALUE;
+                onThrottlingChangedLocked(false);
+            }
         }
     }
 
     @Override
     public void onDeviceStationaryChanged(boolean deviceStationary) {
         synchronized (mLock) {
+            if (!mDeviceIdle) {
+                // stationary detection is only registered while idle - ignore late notifications
+                return;
+            }
+
             if (mDeviceStationary == deviceStationary) {
                 return;
             }
diff --git a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
index a597edd..8fdc22b 100644
--- a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
@@ -59,7 +59,7 @@
     private static final String EXTRA_LOCATION_TAGS = "android:location_allow_listed_tags";
     private static final String LOCATION_TAGS_SEPARATOR = ";";
 
-    private static final long RESET_DELAY_MS = 1000;
+    private static final long RESET_DELAY_MS = 10000;
 
     /**
      * Creates and registers this proxy. If no suitable service is available for the proxy, returns
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 9a76ebd..29ea071 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -108,7 +108,6 @@
 import android.provider.Settings;
 import android.security.AndroidKeyStoreMaintenance;
 import android.security.Authorization;
-import android.security.KeyStore;
 import android.security.keystore.KeyProperties;
 import android.security.keystore.KeyProtection;
 import android.security.keystore.recovery.KeyChainProtectionParams;
@@ -169,6 +168,7 @@
 import java.security.GeneralSecurityException;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
+import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
@@ -292,7 +292,7 @@
     private final IActivityManager mActivityManager;
     private final SyntheticPasswordManager mSpManager;
 
-    private final java.security.KeyStore mJavaKeyStore;
+    private final KeyStore mKeyStore;
     private final RecoverableKeyStoreManager mRecoverableKeyStoreManager;
     private final UnifiedProfilePasswordCache mUnifiedProfilePasswordCache;
 
@@ -564,10 +564,6 @@
             return DeviceStateCache.getInstance();
         }
 
-        public KeyStore getKeyStore() {
-            return KeyStore.getInstance();
-        }
-
         public RecoverableKeyStoreManager getRecoverableKeyStoreManager() {
             return RecoverableKeyStoreManager.getInstance(mContext);
         }
@@ -619,9 +615,9 @@
             return (BiometricManager) mContext.getSystemService(Context.BIOMETRIC_SERVICE);
         }
 
-        public java.security.KeyStore getJavaKeyStore() {
+        public KeyStore getKeyStore() {
             try {
-                java.security.KeyStore ks = java.security.KeyStore.getInstance(
+                KeyStore ks = KeyStore.getInstance(
                         SyntheticPasswordCrypto.androidKeystoreProviderName());
                 ks.load(new AndroidKeyStoreLoadStoreParameter(
                         SyntheticPasswordCrypto.keyNamespace()));
@@ -631,8 +627,7 @@
             }
         }
 
-        public @NonNull UnifiedProfilePasswordCache getUnifiedProfilePasswordCache(
-                java.security.KeyStore ks) {
+        public @NonNull UnifiedProfilePasswordCache getUnifiedProfilePasswordCache(KeyStore ks) {
             return new UnifiedProfilePasswordCache(ks);
         }
 
@@ -654,7 +649,7 @@
     protected LockSettingsService(Injector injector) {
         mInjector = injector;
         mContext = injector.getContext();
-        mJavaKeyStore = injector.getJavaKeyStore();
+        mKeyStore = injector.getKeyStore();
         mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager();
         mHandler = injector.getHandler(injector.getServiceThread());
         mStrongAuth = injector.getStrongAuth();
@@ -676,7 +671,7 @@
         mGatekeeperPasswords = new LongSparseArray<>();
 
         mSpManager = injector.getSyntheticPasswordManager(mStorage);
-        mUnifiedProfilePasswordCache = injector.getUnifiedProfilePasswordCache(mJavaKeyStore);
+        mUnifiedProfilePasswordCache = injector.getUnifiedProfilePasswordCache(mKeyStore);
         mBiometricDeferredQueue = new BiometricDeferredQueue(mSpManager, mHandler);
 
         mRebootEscrowManager = injector.getRebootEscrowManager(new RebootEscrowCallbacks(),
@@ -1482,7 +1477,7 @@
         byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE,
                 storedData.length);
         byte[] decryptionResult;
-        SecretKey decryptionKey = (SecretKey) mJavaKeyStore.getKey(
+        SecretKey decryptionKey = (SecretKey) mKeyStore.getKey(
                 PROFILE_KEY_NAME_DECRYPT + userId, null);
 
         Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
@@ -1875,9 +1870,10 @@
         }
     }
 
-    private void onPostPasswordChanged(LockscreenCredential newCredential, int userHandle) {
-        updatePasswordHistory(newCredential, userHandle);
-        mContext.getSystemService(TrustManager.class).reportEnabledTrustAgentsChanged(userHandle);
+    private void onPostPasswordChanged(LockscreenCredential newCredential, int userId) {
+        updatePasswordHistory(newCredential, userId);
+        mContext.getSystemService(TrustManager.class).reportEnabledTrustAgentsChanged(userId);
+        sendMainUserCredentialChangedNotificationIfNeeded(userId);
     }
 
     /**
@@ -2076,16 +2072,16 @@
             keyGenerator.init(new SecureRandom());
             SecretKey secretKey = keyGenerator.generateKey();
             try {
-                mJavaKeyStore.setEntry(
+                mKeyStore.setEntry(
                         PROFILE_KEY_NAME_ENCRYPT + profileUserId,
-                        new java.security.KeyStore.SecretKeyEntry(secretKey),
+                        new KeyStore.SecretKeyEntry(secretKey),
                         new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
                                 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                                 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                                 .build());
-                mJavaKeyStore.setEntry(
+                mKeyStore.setEntry(
                         PROFILE_KEY_NAME_DECRYPT + profileUserId,
-                        new java.security.KeyStore.SecretKeyEntry(secretKey),
+                        new KeyStore.SecretKeyEntry(secretKey),
                         new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
                                 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                                 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
@@ -2094,7 +2090,7 @@
                                 .setUserAuthenticationValidityDurationSeconds(30)
                                 .build());
                 // Key imported, obtain a reference to it.
-                SecretKey keyStoreEncryptionKey = (SecretKey) mJavaKeyStore.getKey(
+                SecretKey keyStoreEncryptionKey = (SecretKey) mKeyStore.getKey(
                         PROFILE_KEY_NAME_ENCRYPT + profileUserId, null);
                 Cipher cipher = Cipher.getInstance(
                         KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
@@ -2104,7 +2100,7 @@
                 iv = cipher.getIV();
             } finally {
                 // The original key can now be discarded.
-                mJavaKeyStore.deleteEntry(PROFILE_KEY_NAME_ENCRYPT + profileUserId);
+                mKeyStore.deleteEntry(PROFILE_KEY_NAME_ENCRYPT + profileUserId);
             }
         } catch (UnrecoverableKeyException
                 | BadPaddingException | IllegalBlockSizeException | KeyStoreException
@@ -2556,11 +2552,10 @@
         final String encryptAlias = PROFILE_KEY_NAME_ENCRYPT + targetUserId;
         final String decryptAlias = PROFILE_KEY_NAME_DECRYPT + targetUserId;
         try {
-            if (mJavaKeyStore.containsAlias(encryptAlias) ||
-                    mJavaKeyStore.containsAlias(decryptAlias)) {
+            if (mKeyStore.containsAlias(encryptAlias) || mKeyStore.containsAlias(decryptAlias)) {
                 Slogf.i(TAG, "Removing keystore profile key for user %d", targetUserId);
-                mJavaKeyStore.deleteEntry(encryptAlias);
-                mJavaKeyStore.deleteEntry(decryptAlias);
+                mKeyStore.deleteEntry(encryptAlias);
+                mKeyStore.deleteEntry(decryptAlias);
             }
         } catch (KeyStoreException e) {
             // We have tried our best to remove the key.
@@ -3062,7 +3057,6 @@
         setCurrentLskfBasedProtectorId(newProtectorId, userId);
         LockPatternUtils.invalidateCredentialTypeCache();
         synchronizeUnifiedChallengeForProfiles(userId, profilePasswords);
-        sendMainUserCredentialChangedNotificationIfNeeded(userId);
 
         setUserPasswordMetrics(credential, userId);
         mUnifiedProfilePasswordCache.removePassword(userId);
@@ -3457,7 +3451,7 @@
 
     private void dumpKeystoreKeys(IndentingPrintWriter pw) {
         try {
-            final Enumeration<String> aliases = mJavaKeyStore.aliases();
+            final Enumeration<String> aliases = mKeyStore.aliases();
             while (aliases.hasMoreElements()) {
                 pw.println(aliases.nextElement());
             }
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 1f7d549..2a48785 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -851,7 +851,6 @@
         }
     }
 
-    @RequiresPermission(value = Manifest.permission.MEDIA_ROUTING_CONTROL, conditional = true)
     private boolean checkMediaRoutingControlPermission(
             int callerUid, int callerPid, @Nullable String callerPackageName) {
         return PermissionChecker.checkPermissionForDataDelivery(
diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java
index a110e56..1dc86f2 100644
--- a/services/core/java/com/android/server/media/MediaSession2Record.java
+++ b/services/core/java/com/android/server/media/MediaSession2Record.java
@@ -35,12 +35,11 @@
  * Keeps the record of {@link Session2Token} to help send command to the corresponding session.
  */
 // TODO(jaewan): Do not call service method directly -- introduce listener instead.
-public class MediaSession2Record implements MediaSessionRecordImpl {
+public class MediaSession2Record extends MediaSessionRecordImpl {
     private static final String TAG = "MediaSession2Record";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private final Object mLock = new Object();
 
-    private final int mUniqueId;
     @GuardedBy("mLock")
     private final Session2Token mSessionToken;
     @GuardedBy("mLock")
@@ -57,20 +56,18 @@
     private boolean mIsClosed;
 
     private final int mPid;
-    private final ForegroundServiceDelegationOptions mForegroundServiceDelegationOptions;
 
     public MediaSession2Record(
             Session2Token sessionToken,
             MediaSessionService service,
             Looper handlerLooper,
             int pid,
-            int policies,
-            int uniqueId) {
+            int policies) {
         // The lock is required to prevent `Controller2Callback` from using partially initialized
         // `MediaSession2Record.this`.
         synchronized (mLock) {
+            mUniqueId = sNextMediaSessionRecordId.getAndIncrement();
             mSessionToken = sessionToken;
-            mUniqueId = uniqueId;
             mService = service;
             mHandlerExecutor = new HandlerExecutor(new Handler(handlerLooper));
             mController = new MediaController2.Builder(service.getContext(), sessionToken)
@@ -78,32 +75,6 @@
                     .build();
             mPid = pid;
             mPolicies = policies;
-            mForegroundServiceDelegationOptions =
-                    new ForegroundServiceDelegationOptions.Builder()
-                            .setClientPid(mPid)
-                            .setClientUid(getUid())
-                            .setClientPackageName(getPackageName())
-                            .setClientAppThread(null)
-                            .setSticky(false)
-                            .setClientInstanceName(
-                                    "MediaSessionFgsDelegate_"
-                                            + getUid()
-                                            + "_"
-                                            + mPid
-                                            + "_"
-                                            + getPackageName())
-                            .setForegroundServiceTypes(0)
-                            .setDelegationService(
-                                    ForegroundServiceDelegationOptions
-                                            .DELEGATION_SERVICE_MEDIA_PLAYBACK)
-                            .build();
-        }
-    }
-
-    @Override
-    public int getUniqueId() {
-        synchronized (mLock) {
-            return mUniqueId;
         }
     }
 
@@ -128,7 +99,10 @@
 
     @Override
     public ForegroundServiceDelegationOptions getForegroundServiceDelegationOptions() {
-        return mForegroundServiceDelegationOptions;
+        // For an app to be eligible for FGS delegation, it needs a media session liked to a media
+        // notification. Currently, notifications cannot be linked to MediaSession2 so it is not
+        // supported.
+        return null;
     }
 
     @Override
@@ -210,7 +184,7 @@
 
     @Override
     public void dump(PrintWriter pw, String prefix) {
-        pw.println(prefix + "uniqueId=" + mUniqueId);
+        pw.println(prefix + "uniqueId=" + getUniqueId());
         pw.println(prefix + "token=" + mSessionToken);
         pw.println(prefix + "controller=" + mController);
 
@@ -220,7 +194,7 @@
 
     @Override
     public String toString() {
-        return getPackageName() + "/" + mUniqueId + " (userId=" + getUserId() + ")";
+        return getPackageName() + "/" + getUniqueId() + " (userId=" + getUserId() + ")";
     }
 
     private class Controller2Callback extends MediaController2.ControllerCallback {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 1552704..a9a8272 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -96,7 +96,7 @@
  * MediaSession wrapper class instead.
  */
 // TODO(jaewan): Do not call service method directly -- introduce listener instead.
-public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionRecordImpl {
+public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinder.DeathRecipient {
 
     /**
      * {@link android.media.session.MediaSession#setMediaButtonBroadcastReceiver(
@@ -173,7 +173,6 @@
     private final int mUserId;
     private final String mPackageName;
     private final String mTag;
-    private final int mUniqueId;
     private final Bundle mSessionInfo;
     private final ControllerStub mController;
     private final MediaSession.Token mSessionToken;
@@ -231,18 +230,17 @@
             String ownerPackageName,
             ISessionCallback cb,
             String tag,
-            int uniqueId,
             Bundle sessionInfo,
             MediaSessionService service,
             Looper handlerLooper,
             int policies)
             throws RemoteException {
+        mUniqueId = sNextMediaSessionRecordId.getAndIncrement();
         mOwnerPid = ownerPid;
         mOwnerUid = ownerUid;
         mUserId = userId;
         mPackageName = ownerPackageName;
         mTag = tag;
-        mUniqueId = uniqueId;
         mSessionInfo = sessionInfo;
         mController = new ControllerStub();
         mSessionToken = new MediaSession.Token(ownerUid, mController);
@@ -303,16 +301,6 @@
     }
 
     /**
-     * Get the unique id of this session record.
-     *
-     * @return a unique id of this session record.
-     */
-    @Override
-    public int getUniqueId() {
-        return mUniqueId;
-    }
-
-    /**
      * Get the info for this session.
      *
      * @return Info that identifies this session.
@@ -724,7 +712,7 @@
 
     @Override
     public String toString() {
-        return mPackageName + "/" + mTag + "/" + mUniqueId + " (userId=" + mUserId + ")";
+        return mPackageName + "/" + mTag + "/" + getUniqueId() + " (userId=" + mUserId + ")";
     }
 
     @Override
diff --git a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
index e53a2db..e4b2fad 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
@@ -25,39 +25,37 @@
 import com.android.server.media.MediaSessionPolicyProvider.SessionPolicy;
 
 import java.io.PrintWriter;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Common interfaces between {@link MediaSessionRecord} and {@link MediaSession2Record}.
  */
-public interface MediaSessionRecordImpl extends AutoCloseable {
+public abstract class MediaSessionRecordImpl {
 
-    /**
-     * Get the unique id of this session record.
-     *
-     * @return a unique id of this session record.
-     */
-    int getUniqueId();
+    static final AtomicInteger sNextMediaSessionRecordId = new AtomicInteger(1);
+    int mUniqueId;
 
     /**
      * Get the info for this session.
      *
      * @return Info that identifies this session.
      */
-    String getPackageName();
+    public abstract String getPackageName();
 
     /**
      * Get the UID this session was created for.
      *
      * @return The UID for this session.
      */
-    int getUid();
+    public abstract int getUid();
 
     /**
      * Get the user id this session was created for.
      *
      * @return The user id for this session.
      */
-    int getUserId();
+    public abstract int getUserId();
 
     /**
      * Get the {@link ForegroundServiceDelegationOptions} needed for notifying activity manager
@@ -66,7 +64,7 @@
      * @return the {@link ForegroundServiceDelegationOptions} needed for notifying the activity
      *     manager service with changes in the {@link PlaybackState} for this session.
      */
-    ForegroundServiceDelegationOptions getForegroundServiceDelegationOptions();
+    public abstract ForegroundServiceDelegationOptions getForegroundServiceDelegationOptions();
 
     /**
      * Check if this session has system priority and should receive media buttons before any other
@@ -74,7 +72,7 @@
      *
      * @return True if this is a system priority session, false otherwise
      */
-    boolean isSystemPriority();
+    public abstract boolean isSystemPriority();
 
     /**
      * Send a volume adjustment to the session owner. Direction must be one of
@@ -95,7 +93,7 @@
      * @param useSuggested True to use adjustSuggestedStreamVolumeForUid instead of
      *          adjustStreamVolumeForUid
      */
-    void adjustVolume(String packageName, String opPackageName, int pid, int uid,
+    public abstract void adjustVolume(String packageName, String opPackageName, int pid, int uid,
             boolean asSystemService, int direction, int flags, boolean useSuggested);
 
     /**
@@ -105,7 +103,7 @@
      * @return True if the session is active, false otherwise.
      */
     // TODO(jaewan): Find better naming, or remove this from the MediaSessionRecordImpl.
-    boolean isActive();
+    public abstract boolean isActive();
 
     /**
      * Check if the session's playback active state matches with the expectation. This always
@@ -115,7 +113,7 @@
      * @param expected True if playback is expected to be active. False otherwise.
      * @return True if the session's playback matches with the expectation. False otherwise.
      */
-    boolean checkPlaybackActiveState(boolean expected);
+    public abstract boolean checkPlaybackActiveState(boolean expected);
 
     /**
      * Check whether the playback type is local or remote.
@@ -128,7 +126,7 @@
      *
      * @return {@code true} if the playback is local. {@code false} if the playback is remote.
      */
-    boolean isPlaybackTypeLocal();
+    public abstract boolean isPlaybackTypeLocal();
 
     /**
      * Sends media button.
@@ -145,27 +143,27 @@
      * @return {@code true} if the attempt to send media button was successfully.
      *         {@code false} otherwise.
      */
-    boolean sendMediaButton(String packageName, int pid, int uid, boolean asSystemService,
-            KeyEvent ke, int sequenceId, ResultReceiver cb);
+    public abstract boolean sendMediaButton(String packageName, int pid, int uid,
+            boolean asSystemService, KeyEvent ke, int sequenceId, ResultReceiver cb);
 
     /**
      * Returns whether the media session can handle volume key events.
      *
      * @return True if this media session can handle volume key events, false otherwise.
      */
-    boolean canHandleVolumeKey();
+    public abstract boolean canHandleVolumeKey();
 
     /**
      * Get session policies from custom policy provider set when MediaSessionRecord is instantiated.
      * If custom policy does not exist, will return null.
      */
     @SessionPolicy
-    int getSessionPolicies();
+    public abstract int getSessionPolicies();
 
     /**
      * Overwrite session policies that have been set when MediaSessionRecord is instantiated.
      */
-    void setSessionPolicies(@SessionPolicy int policies);
+    public abstract void setSessionPolicies(@SessionPolicy int policies);
 
     /**
      * Dumps internal state
@@ -173,16 +171,37 @@
      * @param pw print writer
      * @param prefix prefix
      */
-    void dump(PrintWriter pw, String prefix);
+    public abstract void dump(PrintWriter pw, String prefix);
 
     /**
-     * Override {@link AutoCloseable#close} to tell it not to throw exception.
+     * Similar to {@link AutoCloseable#close} without throwing an exception.
      */
-    @Override
-    void close();
+    public abstract void close();
+
+    /**
+     * Get the unique id of this session record.
+     *
+     * @return a unique id of this session record.
+     */
+    public int getUniqueId() {
+        return mUniqueId;
+    }
 
     /**
      * Returns whether {@link #close()} is called before.
      */
-    boolean isClosed();
+    public abstract boolean isClosed();
+
+    @Override
+    public final boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || !(o instanceof MediaSessionRecordImpl)) return false;
+        MediaSessionRecordImpl that = (MediaSessionRecordImpl) o;
+        return mUniqueId == that.mUniqueId;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(mUniqueId);
+    }
 }
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 9e98a58..e2163c5 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -106,7 +106,6 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * System implementation of MediaSessionManager
@@ -128,6 +127,22 @@
      */
     private static final String MEDIA_BUTTON_RECEIVER = "media_button_receiver";
 
+    /**
+     * Action reported to UsageStatsManager when a media session becomes active and user engaged
+     * for a given app. App is expected to show an ongoing notification after this.
+     */
+    private static final String USAGE_STATS_ACTION_START = "start";
+
+    /**
+     * Action reported to UsageStatsManager when a media session is no longer active and user
+     * engaged for a given app. If media session only pauses for a brief time the event will not
+     * necessarily be reported in case user is still "engaging" and will restart it momentarily.
+     * In such case, action may be reported after a short delay to ensure user is truly no longer
+     * engaging. Afterwards, the app is no longer expected to show an ongoing notification.
+     */
+    private static final String USAGE_STATS_ACTION_STOP = "stop";
+    private static final String USAGE_STATS_CATEGORY = "android.media";
+
     private final Context mContext;
     private final SessionManagerImpl mSessionManagerImpl;
     private final MessageHandler mHandler = new MessageHandler();
@@ -154,9 +169,8 @@
     private UsageStatsManagerInternal mUsageStatsManagerInternal;
 
     /* Maps uid with all user engaging session tokens associated to it */
-    private final SparseArray<Set<MediaSession.Token>> mUserEngagingSessions = new SparseArray<>();
-
-    private final AtomicInteger mNextMediaSessionRecordId = new AtomicInteger(1);
+    private final SparseArray<Set<MediaSessionRecordImpl>> mUserEngagingSessions =
+            new SparseArray<>();
 
     // The FullUserRecord of the current users. (i.e. The foreground user that isn't a profile)
     // It's always not null after the MediaSessionService is started.
@@ -196,8 +210,7 @@
                                     MediaSessionService.this,
                                     mRecordThread.getLooper(),
                                     pid,
-                                    /* policies= */ 0,
-                                    /* uniqueId= */ mNextMediaSessionRecordId.getAndIncrement());
+                                    /* policies= */ 0);
                     synchronized (mLock) {
                         FullUserRecord user = getFullUserRecordLocked(record.getUserId());
                         if (user != null) {
@@ -613,9 +626,7 @@
         }
         ForegroundServiceDelegationOptions foregroundServiceDelegationOptions =
                 record.getForegroundServiceDelegationOptions();
-        if (foregroundServiceDelegationOptions == null
-                || foregroundServiceDelegationOptions.mClientPid == Process.INVALID_PID) {
-            // This record doesn't support FGS delegation. In practice, this is MediaSession2.
+        if (foregroundServiceDelegationOptions == null) {
             return;
         }
         if (allowRunningInForeground) {
@@ -628,24 +639,24 @@
     }
 
     private void reportMediaInteractionEvent(MediaSessionRecordImpl record, boolean userEngaged) {
-        if (!android.app.usage.Flags.userInteractionTypeApi()
-                || !(record instanceof MediaSessionRecord)) {
+        if (!android.app.usage.Flags.userInteractionTypeApi()) {
             return;
         }
 
         String packageName = record.getPackageName();
         int sessionUid = record.getUid();
-        MediaSession.Token token = ((MediaSessionRecord) record).getSessionToken();
         if (userEngaged) {
             if (!mUserEngagingSessions.contains(sessionUid)) {
                 mUserEngagingSessions.put(sessionUid, new HashSet<>());
-                reportUserInteractionEvent(/* action= */ "start", record.getUserId(), packageName);
+                reportUserInteractionEvent(
+                    USAGE_STATS_ACTION_START, record.getUserId(), packageName);
             }
-            mUserEngagingSessions.get(sessionUid).add(token);
+            mUserEngagingSessions.get(sessionUid).add(record);
         } else if (mUserEngagingSessions.contains(sessionUid)) {
-            mUserEngagingSessions.get(sessionUid).remove(token);
+            mUserEngagingSessions.get(sessionUid).remove(record);
             if (mUserEngagingSessions.get(sessionUid).isEmpty()) {
-                reportUserInteractionEvent(/* action= */ "stop", record.getUserId(), packageName);
+                reportUserInteractionEvent(
+                    USAGE_STATS_ACTION_STOP, record.getUserId(), packageName);
                 mUserEngagingSessions.remove(sessionUid);
             }
         }
@@ -653,7 +664,7 @@
 
     private void reportUserInteractionEvent(String action, int userId, String packageName) {
         PersistableBundle extras = new PersistableBundle();
-        extras.putString(UsageStatsManager.EXTRA_EVENT_CATEGORY, "android.media");
+        extras.putString(UsageStatsManager.EXTRA_EVENT_CATEGORY, USAGE_STATS_CATEGORY);
         extras.putString(UsageStatsManager.EXTRA_EVENT_ACTION, action);
         mUsageStatsManagerInternal.reportUserInteractionEvent(packageName, userId, extras);
     }
@@ -806,7 +817,6 @@
                                 callerPackageName,
                                 cb,
                                 tag,
-                                /* uniqueId= */ mNextMediaSessionRecordId.getAndIncrement(),
                                 sessionInfo,
                                 this,
                                 mRecordThread.getLooper(),
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b5c51af..18b495b 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -727,7 +727,7 @@
      * Map of uid -> UidStateCallbackInfo objects holding the data received from
      * {@link IUidObserver#onUidStateChanged(int, int, long, int)} callbacks. In order to avoid
      * creating a new object for every callback received, we hold onto the object created for each
-     * uid and reuse it.
+     * uid and reuse it until the uid stays alive.
      *
      * Note that the lock used for accessing this object should not be used for anything else and we
      * should not be acquiring new locks or doing any heavy work while this lock is held since this
@@ -800,6 +800,13 @@
                 Clock.systemUTC());
     }
 
+    @VisibleForTesting
+    UidState getUidStateForTest(int uid) {
+        synchronized (mUidRulesFirstLock) {
+            return mUidState.get(uid);
+        }
+    }
+
     static class Dependencies {
         final Context mContext;
         final NetworkStatsManager mNetworkStatsManager;
@@ -1245,7 +1252,7 @@
                 if (isUidStateChangeRelevant(callbackInfo, procState, procStateSeq, capability)) {
                     callbackInfo.update(uid, procState, procStateSeq, capability);
                     if (!callbackInfo.isPending) {
-                        mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED, callbackInfo)
+                        mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED, uid, 0)
                                 .sendToTarget();
                         callbackInfo.isPending = true;
                     }
@@ -1254,6 +1261,9 @@
         }
 
         @Override public void onUidGone(int uid, boolean disabled) {
+            synchronized (mUidStateCallbackInfos) {
+                mUidStateCallbackInfos.remove(uid);
+            }
             mUidEventHandler.obtainMessage(UID_MSG_GONE, uid, 0).sendToTarget();
         }
     };
@@ -5859,13 +5869,13 @@
     private final Handler.Callback mUidEventHandlerCallback = new Handler.Callback() {
         @Override
         public boolean handleMessage(Message msg) {
+            final int uid = msg.arg1;
             switch (msg.what) {
                 case UID_MSG_STATE_CHANGED: {
-                    handleUidChanged((UidStateCallbackInfo) msg.obj);
+                    handleUidChanged(uid);
                     return true;
                 }
                 case UID_MSG_GONE: {
-                    final int uid = msg.arg1;
                     handleUidGone(uid);
                     return true;
                 }
@@ -5876,23 +5886,27 @@
         }
     };
 
-    void handleUidChanged(@NonNull UidStateCallbackInfo uidStateCallbackInfo) {
+    void handleUidChanged(int uid) {
         Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidStateChanged");
         try {
-            boolean updated;
-            final int uid;
             final int procState;
             final long procStateSeq;
             final int capability;
-            synchronized (mUidRulesFirstLock) {
-                synchronized (mUidStateCallbackInfos) {
-                    uid = uidStateCallbackInfo.uid;
-                    procState = uidStateCallbackInfo.procState;
-                    procStateSeq = uidStateCallbackInfo.procStateSeq;
-                    capability = uidStateCallbackInfo.capability;
-                    uidStateCallbackInfo.isPending = false;
+            synchronized (mUidStateCallbackInfos) {
+                final UidStateCallbackInfo uidStateCallbackInfo = mUidStateCallbackInfos.get(uid);
+                if (uidStateCallbackInfo == null) {
+                    // This can happen if UidObserver#onUidGone gets called before we reach
+                    // here. In this case, there is no point in processing this change as this
+                    // will immediately be followed by a call to handleUidGone anyway.
+                    return;
                 }
-
+                procState = uidStateCallbackInfo.procState;
+                procStateSeq = uidStateCallbackInfo.procStateSeq;
+                capability = uidStateCallbackInfo.capability;
+                uidStateCallbackInfo.isPending = false;
+            }
+            final boolean updated;
+            synchronized (mUidRulesFirstLock) {
                 // We received a uid state change callback, add it to the history so that it
                 // will be useful for debugging.
                 mLogger.uidStateChanged(uid, procState, procStateSeq, capability);
@@ -5915,7 +5929,15 @@
     void handleUidGone(int uid) {
         Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidGone");
         try {
-            boolean updated;
+            synchronized (mUidStateCallbackInfos) {
+                if (mUidStateCallbackInfos.contains(uid)) {
+                    // This can happen if UidObserver#onUidStateChanged gets called before we
+                    // reach here. In this case, there is no point in processing this change as this
+                    // will immediately be followed by a call to handleUidChanged anyway.
+                    return;
+                }
+            }
+            final boolean updated;
             synchronized (mUidRulesFirstLock) {
                 updated = removeUidStateUL(uid);
             }
diff --git a/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java b/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java
index ab650af..27b8574 100644
--- a/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java
+++ b/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java
@@ -65,7 +65,9 @@
         mColorDisplayManager = context.getSystemService(ColorDisplayManager.class);
         mPowerManager = context.getSystemService(PowerManager.class);
         mUiModeManager = context.getSystemService(UiModeManager.class);
-        mWallpaperManager = context.getSystemService(WallpaperManager.class);
+        WallpaperManager wallpaperManager = context.getSystemService(WallpaperManager.class);
+        mWallpaperManager = wallpaperManager != null && wallpaperManager.isWallpaperSupported()
+                ? wallpaperManager : null;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3a7ac0b..ba5882c 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -12050,11 +12050,12 @@
         @Override
         public void onServiceAdded(ManagedServiceInfo info) {
             if (lifetimeExtensionRefactor()) {
-                // Generally, only System or System UI should have the permissions to call
-                // registerSystemService.
-                // isCallerSystemorPhone tells us whether the caller is System. Then, if it's not
-                // the system, we know it's system UI.
-                info.isSystemUi = !isCallerSystemOrPhone();
+                // We explicitly check the status bar permission for the uid in the info object.
+                // We can't use the calling uid here because it's probably always system server.
+                // Note that this will also be true for the shell.
+                info.isSystemUi = getContext().checkPermission(
+                        android.Manifest.permission.STATUS_BAR_SERVICE, -1, info.uid)
+                        == PERMISSION_GRANTED;
             }
             final INotificationListener listener = (INotificationListener) info.service;
             final NotificationRankingUpdate update;
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index eed0eec..6857869 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1285,8 +1285,8 @@
      */
     private static void updateZenDeviceEffects(ZenRule zenRule,
             @Nullable ZenDeviceEffects newEffects, boolean isFromApp, boolean updateBitmask) {
+        // Same as with ZenPolicy, supplying null effects means keeping the previous ones.
         if (newEffects == null) {
-            zenRule.zenDeviceEffects = null;
             return;
         }
 
diff --git a/services/core/java/com/android/server/om/IdmapDaemon.java b/services/core/java/com/android/server/om/IdmapDaemon.java
index 15cfca5..1b22154 100644
--- a/services/core/java/com/android/server/om/IdmapDaemon.java
+++ b/services/core/java/com/android/server/om/IdmapDaemon.java
@@ -51,8 +51,15 @@
     // before stopping the service.
     private static final int SERVICE_TIMEOUT_MS = 10000;
 
-    // The amount of time in milliseconds to wait when attempting to connect to idmap service.
-    private static final int SERVICE_CONNECT_TIMEOUT_MS = 5000;
+    // The device may enter CPU sleep while waiting for the service startup, and in that mode
+    // the uptime doesn't increment. Thus, we need to have two timeouts: a smaller one for the
+    // uptime and a longer one for the wall time in case when the device never advances the uptime,
+    // so the watchdog won't get triggered.
+
+    // The amount of uptime in milliseconds to wait when attempting to connect to idmap service.
+    private static final int SERVICE_CONNECT_UPTIME_TIMEOUT_MS = 5000;
+    // The amount of wall time in milliseconds to wait.
+    private static final int SERVICE_CONNECT_WALLTIME_TIMEOUT_MS = 30000;
     private static final int SERVICE_CONNECT_INTERVAL_SLEEP_MS = 5;
 
     private static final String IDMAP_DAEMON = "idmap2d";
@@ -274,20 +281,29 @@
             }
         }
 
-        final long endMillis = SystemClock.uptimeMillis() + SERVICE_CONNECT_TIMEOUT_MS;
+        long uptimeMillis = SystemClock.uptimeMillis();
+        final long endUptimeMillis = uptimeMillis + SERVICE_CONNECT_UPTIME_TIMEOUT_MS;
+        long walltimeMillis = SystemClock.elapsedRealtime();
+        final long endWalltimeMillis = walltimeMillis + SERVICE_CONNECT_WALLTIME_TIMEOUT_MS;
+
         do {
             final IBinder binder = ServiceManager.getService(IDMAP_SERVICE);
             if (binder != null) {
                 binder.linkToDeath(
-                        () -> Slog.w(TAG, String.format("service '%s' died", IDMAP_SERVICE)), 0);
+                        () -> Slog.w(TAG,
+                                TextUtils.formatSimple("service '%s' died", IDMAP_SERVICE)), 0);
                 return binder;
             }
             SystemClock.sleep(SERVICE_CONNECT_INTERVAL_SLEEP_MS);
-        } while (SystemClock.uptimeMillis() <= endMillis);
+        } while ((uptimeMillis = SystemClock.uptimeMillis()) <= endUptimeMillis
+                && (walltimeMillis = SystemClock.elapsedRealtime()) <= endWalltimeMillis);
 
         throw new TimeoutException(
-            String.format("Failed to connect to '%s' in %d milliseconds", IDMAP_SERVICE,
-                    SERVICE_CONNECT_TIMEOUT_MS));
+                TextUtils.formatSimple("Failed to connect to '%s' in %d/%d ms (spent %d/%d ms)",
+                        IDMAP_SERVICE, SERVICE_CONNECT_UPTIME_TIMEOUT_MS,
+                        SERVICE_CONNECT_WALLTIME_TIMEOUT_MS,
+                        uptimeMillis - endUptimeMillis + SERVICE_CONNECT_UPTIME_TIMEOUT_MS,
+                        walltimeMillis - endWalltimeMillis + SERVICE_CONNECT_WALLTIME_TIMEOUT_MS));
     }
 
     private static void stopIdmapService() {
diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
index a4c4347..0abe50f 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.ondeviceintelligence;
 
+import static android.service.ondeviceintelligence.OnDeviceIntelligenceService.OnDeviceUpdateProcessingException.PROCESSING_UPDATE_STATUS_CONNECTION_FAILED;
+
 import android.Manifest;
 import android.annotation.NonNull;
 import android.app.AppGlobals;
@@ -36,6 +38,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
+import android.os.Bundle;
 import android.os.ICancellationSignal;
 import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
@@ -43,8 +46,12 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
+import android.service.ondeviceintelligence.IOnDeviceIntelligenceService;
 import android.service.ondeviceintelligence.IOnDeviceTrustedInferenceService;
+import android.service.ondeviceintelligence.IRemoteProcessingService;
 import android.service.ondeviceintelligence.IRemoteStorageService;
+import android.service.ondeviceintelligence.IProcessingUpdateStatusCallback;
+import android.service.ondeviceintelligence.OnDeviceIntelligenceService;
 import android.text.TextUtils;
 import android.util.Slog;
 
@@ -59,10 +66,11 @@
 import java.util.Set;
 
 /**
- * This is the system service for handling calls on the {@link OnDeviceIntelligenceManager}. This
+ * This is the system service for handling calls on the
+ * {@link android.app.ondeviceintelligence.OnDeviceIntelligenceManager}. This
  * service holds connection references to the underlying remote services i.e. the isolated service
- * {@link android.service.ondeviceintelligence.OnDeviceTrustedInferenceService} and a regular
- * service counter part {@link android.service.ondeviceintelligence.OnDeviceIntelligenceService}.
+ * {@link  OnDeviceTrustedInferenceService} and a regular
+ * service counter part {@link OnDeviceIntelligenceService}.
  *
  * Note: Both the remote services run under the SYSTEM user, as we cannot have separate instance of
  * the Inference service for each user, due to possible high memory footprint.
@@ -313,10 +321,48 @@
                 mRemoteOnDeviceIntelligenceService = new RemoteOnDeviceIntelligenceService(mContext,
                         ComponentName.unflattenFromString(serviceName),
                         UserHandle.SYSTEM.getIdentifier());
+                mRemoteOnDeviceIntelligenceService.setServiceLifecycleCallbacks(
+                        new ServiceConnector.ServiceLifecycleCallbacks<>() {
+                            @Override
+                            public void onConnected(
+                                    @NonNull IOnDeviceIntelligenceService service) {
+                                try {
+                                    service.registerRemoteServices(
+                                            getRemoteProcessingService());
+                                } catch (RemoteException ex) {
+                                    Slog.w(TAG, "Failed to send connected event", ex);
+                                }
+                            }
+                        });
             }
         }
     }
 
+    @NonNull
+    private IRemoteProcessingService.Stub getRemoteProcessingService() {
+        return new IRemoteProcessingService.Stub() {
+            @Override
+            public void updateProcessingState(
+                    Bundle processingState,
+                    IProcessingUpdateStatusCallback callback) {
+                try {
+                    ensureRemoteTrustedInferenceServiceInitialized();
+                    mRemoteInferenceService.post(
+                            service -> service.updateProcessingState(
+                                    processingState, callback));
+                } catch (RemoteException unused) {
+                    try {
+                        callback.onFailure(
+                                PROCESSING_UPDATE_STATUS_CONNECTION_FAILED,
+                                "Received failure invoking the remote processing service.");
+                    } catch (RemoteException ex) {
+                        Slog.w(TAG, "Failed to send failure status.", ex);
+                    }
+                }
+            }
+        };
+    }
+
     private void ensureRemoteTrustedInferenceServiceInitialized() throws RemoteException {
         synchronized (mLock) {
             if (mRemoteInferenceService == null) {
@@ -332,6 +378,7 @@
                             public void onConnected(
                                     @NonNull IOnDeviceTrustedInferenceService service) {
                                 try {
+                                    ensureRemoteIntelligenceServiceInitialized();
                                     service.registerRemoteStorageService(
                                             getIRemoteStorageService());
                                 } catch (RemoteException ex) {
@@ -358,8 +405,7 @@
             @Override
             public void getReadOnlyFeatureFileDescriptorMap(
                     Feature feature,
-                    RemoteCallback remoteCallback)
-                    throws RemoteException {
+                    RemoteCallback remoteCallback) {
                 mRemoteOnDeviceIntelligenceService.post(
                         service -> service.getReadOnlyFeatureFileDescriptorMap(
                                 feature, remoteCallback));
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 8452c0e..4f86adf 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -21,7 +21,6 @@
 import android.Manifest;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
-import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.admin.DevicePolicyManager;
 import android.app.role.RoleManager;
@@ -39,6 +38,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -96,6 +96,7 @@
     private static final long DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS = 30 * 1000;
 
     private final Object mLock = new Object();
+    private final Injector mInjector;
     private final Context mContext;
     private final AppOpsManager mAppOps;
     private final TelephonyManager mTelephonyManager;
@@ -345,6 +346,14 @@
         AtomicFile getMappingFile() {
             return mMappingFile;
         }
+
+        UserManager getUserManager() {
+            return mContext.getSystemService(UserManager.class);
+        }
+
+        DevicePolicyManager getDevicePolicyManager() {
+            return mContext.getSystemService(DevicePolicyManager.class);
+        }
     }
 
     BugreportManagerServiceImpl(Context context) {
@@ -356,6 +365,7 @@
 
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     BugreportManagerServiceImpl(Injector injector) {
+        mInjector = injector;
         mContext = injector.getContext();
         mAppOps = mContext.getSystemService(AppOpsManager.class);
         mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
@@ -388,12 +398,7 @@
         int callingUid = Binder.getCallingUid();
         enforcePermission(callingPackage, callingUid, bugreportMode
                 == BugreportParams.BUGREPORT_MODE_TELEPHONY /* checkCarrierPrivileges */);
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            ensureUserCanTakeBugReport(bugreportMode);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
+        ensureUserCanTakeBugReport(bugreportMode);
 
         Slogf.i(TAG, "Starting bugreport for %s / %d", callingPackage, callingUid);
         synchronized (mLock) {
@@ -432,7 +437,6 @@
     @RequiresPermission(value = Manifest.permission.DUMP, conditional = true)
     public void retrieveBugreport(int callingUidUnused, String callingPackage, int userId,
             FileDescriptor bugreportFd, String bugreportFile,
-
             boolean keepBugreportOnRetrievalUnused, IDumpstateListener listener) {
         int callingUid = Binder.getCallingUid();
         enforcePermission(callingPackage, callingUid, false);
@@ -564,54 +568,59 @@
     }
 
     /**
-     * Validates that the current user is an admin user or, when bugreport is requested remotely
-     * that the current user is an affiliated user.
+     * Validates that the calling user is an admin user or, when bugreport is requested remotely
+     * that the user is an affiliated user.
      *
-     * @throws IllegalArgumentException if the current user is not an admin user
+     * @throws IllegalArgumentException if the calling user or the parent of the calling profile
+     *                                  user is not an admin user.
      */
     private void ensureUserCanTakeBugReport(int bugreportMode) {
-        UserInfo currentUser = null;
+        // Get the calling userId before clearing the caller identity.
+        int effectiveCallingUserId = UserHandle.getUserId(Binder.getCallingUid());
+        boolean isAdminUser = false;
+        final long identity = Binder.clearCallingIdentity();
         try {
-            currentUser = ActivityManager.getService().getCurrentUser();
-        } catch (RemoteException e) {
-            // Impossible to get RemoteException for an in-process call.
+            UserInfo profileParent =
+                    mInjector.getUserManager().getProfileParent(effectiveCallingUserId);
+            if (profileParent == null) {
+                isAdminUser = mInjector.getUserManager().isUserAdmin(effectiveCallingUserId);
+            } else {
+                // If the caller is a profile, we need to check its parent user instead.
+                // Therefore setting the profile parent user as the effective calling user.
+                effectiveCallingUserId = profileParent.id;
+                isAdminUser = profileParent.isAdmin();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
-
-        if (currentUser == null) {
-            logAndThrow("There is no current user, so no bugreport can be requested.");
-        }
-
-        if (!currentUser.isAdmin()) {
+        if (!isAdminUser) {
             if (bugreportMode == BugreportParams.BUGREPORT_MODE_REMOTE
-                    && isCurrentUserAffiliated(currentUser.id)) {
+                    && isUserAffiliated(effectiveCallingUserId)) {
                 return;
             }
-            logAndThrow(TextUtils.formatSimple("Current user %s is not an admin user."
-                    + " Only admin users are allowed to take bugreport.", currentUser.id));
+            logAndThrow(TextUtils.formatSimple("Calling user %s is not an admin user."
+                    + " Only admin users and their profiles are allowed to take bugreport.",
+                    effectiveCallingUserId));
         }
     }
 
     /**
-     * Returns {@code true} if the device has device owner and the current user is affiliated
+     * Returns {@code true} if the device has device owner and the specified user is affiliated
      * with the device owner.
      */
-    private boolean isCurrentUserAffiliated(int currentUserId) {
-        DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
+    private boolean isUserAffiliated(int userId) {
+        DevicePolicyManager dpm = mInjector.getDevicePolicyManager();
         int deviceOwnerUid = dpm.getDeviceOwnerUserId();
         if (deviceOwnerUid == UserHandle.USER_NULL) {
             return false;
         }
 
-        int callingUserId = UserHandle.getUserId(Binder.getCallingUid());
-
-        Slog.i(TAG, "callingUid: " + callingUserId + " deviceOwnerUid: " + deviceOwnerUid
-                + " currentUserId: " + currentUserId);
-
-        if (callingUserId != deviceOwnerUid) {
-            logAndThrow("Caller is not device owner on provisioned device.");
+        if (DEBUG) {
+            Slog.d(TAG, "callingUid: " + userId + " deviceOwnerUid: " + deviceOwnerUid);
         }
-        if (!dpm.isAffiliatedUser(currentUserId)) {
-            logAndThrow("Current user is not affiliated to the device owner.");
+
+        if (userId != deviceOwnerUid && !dpm.isAffiliatedUser(userId)) {
+            logAndThrow("User " + userId + " is not affiliated to the device owner.");
         }
         return true;
     }
diff --git a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
index 5ad5507..5ebcca8 100644
--- a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
@@ -626,7 +626,7 @@
             // version.  If so, we deactivate FRP and set the secret to the default value.
             if (isUpgradingFromPreVRelease()) {
                 Slog.w(TAG, "Upgrading from Android 14 or lower, defaulting FRP secret");
-                writeFrpMagicAndDefaultSecretLocked();
+                writeFrpMagicAndDefaultSecret();
                 mFrpActive = false;
                 return true;
             }
@@ -726,7 +726,7 @@
         synchronized (mLock) {
             if (!hasFrpSecretMagic()) {
                 Slog.i(TAG, "No FRP secret magic, system must have been upgraded.");
-                writeFrpMagicAndDefaultSecretLocked();
+                writeFrpMagicAndDefaultSecret();
             }
         }
 
@@ -748,7 +748,7 @@
         }
     }
 
-    private void writeFrpMagicAndDefaultSecretLocked() {
+    private void writeFrpMagicAndDefaultSecret() {
         try (FileChannel channel = getBlockOutputChannelIgnoringFrp()) {
             synchronized (mLock) {
                 Slog.i(TAG, "Writing default FRP secret");
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index a1dac04..4bfd077 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -17,6 +17,8 @@
 package com.android.server.pm;
 
 import static android.content.pm.Flags.disallowSdkLibsToBeApps;
+import static android.content.pm.PackageManager.APP_METADATA_SOURCE_APK;
+import static android.content.pm.PackageManager.APP_METADATA_SOURCE_INSTALLER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
@@ -43,11 +45,11 @@
 import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
 import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
 
+import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.APP_METADATA_FILE_NAME;
 import static com.android.server.pm.DexOptHelper.useArtService;
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
 import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
-import static com.android.server.pm.PackageManagerService.APP_METADATA_FILE_NAME;
 import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
 import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
 import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
@@ -701,7 +703,7 @@
                     pkgSetting.setUninstallReason(PackageManager.UNINSTALL_REASON_UNKNOWN, userId);
                     pkgSetting.setFirstInstallTime(System.currentTimeMillis(), userId);
                     // Clear any existing archive state.
-                    mPm.mInstallerService.mPackageArchiver.clearArchiveState(packageName, userId);
+                    mPm.mInstallerService.mPackageArchiver.clearArchiveState(pkgSetting, userId);
                     mPm.mSettings.writePackageRestrictionsLPr(userId);
                     mPm.mSettings.writeKernelMappingLPr(pkgSetting);
                     installed = true;
@@ -829,7 +831,8 @@
 
         if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
 
-        if (request.getReturnCode() == PackageManager.INSTALL_SUCCEEDED && doRestore) {
+        final boolean succeeded = request.getReturnCode() == PackageManager.INSTALL_SUCCEEDED;
+        if (succeeded && doRestore) {
             // Pass responsibility to the Backup Manager.  It will perform a
             // restore if appropriate, then pass responsibility back to the
             // Package Manager to run the post-install observer callbacks
@@ -843,10 +846,27 @@
         // need to be snapshotted or restored for the package.
         //
         // TODO(narayan): Get this working for cases where userId == UserHandle.USER_ALL.
-        if (request.getReturnCode() == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) {
+        if (succeeded && !doRestore && update) {
             doRestore = performRollbackManagerRestore(userId, token, request);
         }
 
+        if (succeeded && !request.hasPostInstallRunnable()) {
+            boolean hasNeverBeenRestored =
+                    packageSetting != null && packageSetting.isPendingRestore();
+            request.setPostInstallRunnable(() -> {
+                // Permissions should be restored on each user that has the app installed for the
+                // first time, unless it's an unarchive install for an archived app, in which case
+                // the permissions should be restored on each user that has the app updated.
+                int[] userIdsToRestorePermissions = hasNeverBeenRestored
+                        ? request.getUpdateBroadcastUserIds()
+                        : request.getFirstTimeBroadcastUserIds();
+                for (int restorePermissionUserId : userIdsToRestorePermissions) {
+                    mPm.restorePermissionsAndUpdateRolesForNewUserInstall(request.getName(),
+                            restorePermissionUserId);
+                }
+            });
+        }
+
         if (doRestore) {
             if (packageSetting != null) {
                 synchronized (mPm.mLock) {
@@ -1060,7 +1080,7 @@
                     reconciledPackages = ReconcilePackageUtils.reconcilePackages(
                             requests, Collections.unmodifiableMap(mPm.mPackages),
                             versionInfos, mSharedLibraries, mPm.mSettings.getKeySetManagerService(),
-                            mPm.mSettings);
+                            mPm.mSettings, mPm.mInjector.getSystemConfig());
                 } catch (ReconcileFailure e) {
                     for (InstallRequest request : requests) {
                         request.setError("Reconciliation failed...", e);
@@ -1150,6 +1170,7 @@
 
     @GuardedBy("mPm.mInstallLock")
     private void preparePackageLI(InstallRequest request) throws PrepareFailure {
+        final int[] allUsers =  mPm.mUserManager.getUserIds();
         final int installFlags = request.getInstallFlags();
         final boolean onExternal = request.getVolumeUuid() != null;
         final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
@@ -1425,7 +1446,7 @@
 
                 systemApp = ps.isSystem();
                 request.setOriginUsers(ps.queryUsersInstalledOrHasData(
-                        mPm.mUserManager.getUserIds()));
+                        allUsers));
             }
 
             final int numGroups = ArrayUtils.size(parsedPackage.getPermissionGroups());
@@ -1683,7 +1704,6 @@
 
                 final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
 
-                final int[] allUsers;
                 final int[] installedUsers;
                 final int[] uninstalledUsers;
 
@@ -1776,7 +1796,6 @@
                     }
 
                     // In case of rollback, remember per-user/profile install state
-                    allUsers = mPm.mUserManager.getUserIds();
                     installedUsers = ps.queryInstalledUsers(allUsers, true);
                     uninstalledUsers = ps.queryInstalledUsers(allUsers, false);
 
@@ -2200,17 +2219,23 @@
             final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
             if (ps != null) {
                 installRequest.setNewUsers(
-                        ps.queryInstalledUsers(mPm.mUserManager.getUserIds(), true));
+                        ps.queryInstalledUsers(allUsers, true));
                 ps.setUpdateAvailable(false /*updateAvailable*/);
 
                 File appMetadataFile = new File(ps.getPath(), APP_METADATA_FILE_NAME);
                 if (appMetadataFile.exists()) {
                     ps.setAppMetadataFilePath(appMetadataFile.getAbsolutePath());
                     if (Flags.aslInApkAppMetadataSource()) {
-                        ps.setAppMetadataSource(PackageManager.APP_METADATA_SOURCE_INSTALLER);
+                        ps.setAppMetadataSource(APP_METADATA_SOURCE_INSTALLER);
                     }
                 } else {
-                    ps.setAppMetadataFilePath(null);
+                    if (Flags.aslInApkAppMetadataSource()
+                            && parsedPackage.isAppMetadataFileInApk()) {
+                        ps.setAppMetadataFilePath(appMetadataFile.getAbsolutePath());
+                        ps.setAppMetadataSource(APP_METADATA_SOURCE_APK);
+                    } else {
+                        ps.setAppMetadataFilePath(null);
+                    }
                 }
             }
             if (installRequest.getReturnCode() == PackageManager.INSTALL_SUCCEEDED) {
@@ -2301,7 +2326,7 @@
                 // Retrieve the overlays for shared libraries of the package.
                 if (!ps.getPkgState().getUsesLibraryInfos().isEmpty()) {
                     for (SharedLibraryWrapper sharedLib : ps.getPkgState().getUsesLibraryInfos()) {
-                        for (int currentUserId : UserManagerService.getInstance().getUserIds()) {
+                        for (int currentUserId : allUsers) {
                             if (sharedLib.getType() != SharedLibraryInfo.TYPE_DYNAMIC) {
                                 // TODO(146804378): Support overlaying static shared libraries
                                 continue;
@@ -2327,7 +2352,7 @@
                                 installerPackageName);
                     }
                     // Clear any existing archive state.
-                    mPm.mInstallerService.mPackageArchiver.clearArchiveState(pkgName, userId);
+                    mPm.mInstallerService.mPackageArchiver.clearArchiveState(ps, userId);
                 } else if (allUsers != null) {
                     // The caller explicitly specified INSTALL_ALL_USERS flag.
                     // Thus, updating the settings to install the app for all users.
@@ -2351,7 +2376,7 @@
                                         installerPackageName);
                             }
                             // Clear any existing archive state.
-                            mPm.mInstallerService.mPackageArchiver.clearArchiveState(pkgName,
+                            mPm.mInstallerService.mPackageArchiver.clearArchiveState(ps,
                                     currentUserId);
                         } else {
                             ps.setInstalled(false, currentUserId);
@@ -2390,9 +2415,8 @@
                 }
 
                 // Set install reason for users that are having the package newly installed.
-                final int[] allUsersList = mPm.mUserManager.getUserIds();
                 if (userId == UserHandle.USER_ALL) {
-                    for (int currentUserId : allUsersList) {
+                    for (int currentUserId : allUsers) {
                         if (!previousUserIds.contains(currentUserId)
                                 && ps.getInstalled(currentUserId)) {
                             ps.setInstallReason(installReason, currentUserId);
@@ -2412,7 +2436,7 @@
                 }
 
                 // Ensure that the uninstall reason is UNKNOWN for users with the package installed.
-                for (int currentUserId : allUsersList) {
+                for (int currentUserId : allUsers) {
                     if (ps.getInstalled(currentUserId)) {
                         ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, currentUserId);
                     }
@@ -2851,7 +2875,6 @@
             mPm.notifyInstantAppPackageInstalled(request.getPkg().getPackageName(),
                     request.getNewUsers());
 
-            request.populateBroadcastUsers();
             final int[] firstUserIds = request.getFirstTimeBroadcastUserIds();
 
             if (request.getPkg().getStaticSharedLibraryName() == null) {
@@ -2863,12 +2886,6 @@
                     mPm.mRequiredInstallerPackage,
                     /* packageSender= */ mPm, launchedForRestore, killApp, update, archived);
 
-            // Work that needs to happen on first install within each user
-            for (int userId : firstUserIds) {
-                mPm.restorePermissionsAndUpdateRolesForNewUserInstall(packageName,
-                        userId);
-            }
-
             if (request.isAllNewUsers() && !update) {
                 mPm.notifyPackageAdded(packageName, request.getAppId());
             } else {
@@ -3793,7 +3810,7 @@
                                 mPm.mPackages, Collections.singletonMap(pkgName,
                                         mPm.getSettingsVersionForPackage(parsedPackage)),
                                 mSharedLibraries, mPm.mSettings.getKeySetManagerService(),
-                                mPm.mSettings);
+                                mPm.mSettings, mPm.mInjector.getSystemConfig());
                 if ((scanFlags & SCAN_AS_APEX) == 0) {
                     appIdCreated = optimisticallyRegisterAppId(installRequest);
                 } else {
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 4fb0c22..43075a2 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -692,6 +692,14 @@
         }
     }
 
+    public void setPostInstallRunnable(Runnable runnable) {
+        mPostInstallRunnable = runnable;
+    }
+
+    public boolean hasPostInstallRunnable() {
+        return mPostInstallRunnable != null;
+    }
+
     public void runPostInstallRunnable() {
         if (mPostInstallRunnable != null) {
             mPostInstallRunnable.run();
@@ -753,6 +761,7 @@
 
     public void setNewUsers(int[] newUsers) {
         mNewUsers = newUsers;
+        populateBroadcastUsers();
     }
 
     public void setOriginPackage(String originPackage) {
@@ -829,10 +838,11 @@
     }
 
     /**
-     *  Determine the set of users who are adding this package for the first time vs. those who are
-     *  seeing an update.
+     *  Determine the set of users who are adding this package for the first time (aka "new" users)
+     *  vs. those who are seeing an update (aka "update" users). The lists can be calculated as soon
+     *  as the "new" users are set.
      */
-    public void populateBroadcastUsers() {
+    private void populateBroadcastUsers() {
         assertScanResultExists();
         mFirstTimeBroadcastUserIds = EMPTY_INT_ARRAY;
         mFirstTimeBroadcastInstantUserIds = EMPTY_INT_ARRAY;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index d8d8dd2..6b56b85 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -22,8 +22,8 @@
 import static android.app.AppOpsManager.MODE_IGNORED;
 import static android.app.AppOpsManager.OP_ARCHIVE_ICON_OVERLAY;
 import static android.app.AppOpsManager.OP_UNARCHIVAL_CONFIRMATION;
-import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
-import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
+import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
+import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
 import static android.app.PendingIntent.FLAG_IMMUTABLE;
 import static android.app.PendingIntent.FLAG_MUTABLE;
 import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
@@ -161,6 +161,9 @@
 public class LauncherAppsService extends SystemService {
     private static final String WM_TRACE_DIR = "/data/misc/wmtrace/";
     private static final String VC_FILE_SUFFIX = ".vc";
+    // TODO(b/310027945): Update the intent name.
+    private static final String PS_SETTINGS_INTENT =
+            "com.android.settings.action.PRIVATE_SPACE_SETUP_FLOW";
 
     private static final Set<PosixFilePermission> WM_TRACE_FILE_PERMISSIONS = Set.of(
             PosixFilePermission.OWNER_WRITE,
@@ -1777,6 +1780,27 @@
             }
         }
 
+        @Override
+        public @Nullable IntentSender getPrivateSpaceSettingsIntent() {
+            if (!canAccessHiddenProfile(getCallingUid(), getCallingPid())) {
+                Slog.e(TAG, "Caller cannot access hidden profiles");
+                return null;
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                Intent psSettingsIntent = new Intent(PS_SETTINGS_INTENT);
+                psSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+                final PendingIntent pi = PendingIntent.getActivity(mContext,
+                        /* requestCode */ 0,
+                        psSettingsIntent,
+                        PendingIntent.FLAG_IMMUTABLE | FLAG_UPDATE_CURRENT);
+                return pi == null ? null : pi.getIntentSender();
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
         @Nullable
         private IntentSender buildAppMarketIntentSenderForUser(@NonNull UserHandle user) {
             Intent appMarketIntent = new Intent(Intent.ACTION_MAIN);
@@ -2209,8 +2233,10 @@
             for (UserHandle user : users) {
                 mPackageManagerInternal.forEachInstalledPackage(pkg -> {
                     final String packageName = pkg.getPackageName();
-                    if (mPackageManagerInternal.getIncrementalStatesInfo(packageName,
-                            Process.myUid(), user.getIdentifier()).isLoading()) {
+                    final IncrementalStatesInfo info =
+                            mPackageManagerInternal.getIncrementalStatesInfo(packageName,
+                                    Process.myUid(), user.getIdentifier());
+                    if (info != null && info.isLoading()) {
                         mPackageManagerInternal.registerInstalledLoadingProgressCallback(
                                 packageName, new PackageLoadingProgressCallback(packageName, user),
                                 user.getIdentifier());
diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java
index cdd52a4..ef8453d 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -21,7 +21,7 @@
 import static android.app.ActivityManager.START_PERMISSION_DENIED;
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_IGNORED;
-import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
+import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
 import static android.content.pm.ArchivedActivityInfo.bytesFromBitmap;
 import static android.content.pm.ArchivedActivityInfo.drawableToBitmap;
 import static android.content.pm.PackageInstaller.EXTRA_UNARCHIVE_STATUS;
@@ -356,19 +356,34 @@
     }
 
     void clearArchiveState(String packageName, int userId) {
+        final PackageSetting ps;
         synchronized (mPm.mLock) {
-            PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
-            if (ps != null) {
-                ps.setArchiveState(/* archiveState= */ null, userId);
-            }
+            ps = mPm.mSettings.getPackageLPr(packageName);
         }
-        File iconsDir = getIconsDir(packageName, userId);
+        clearArchiveState(ps, userId);
+    }
+
+    void clearArchiveState(PackageSetting ps, int userId) {
+        synchronized (mPm.mLock) {
+            if (ps == null || ps.getUserStateOrDefault(userId).getArchiveState() == null) {
+                // No archive states to clear
+                return;
+            }
+            if (DEBUG) {
+                Slog.e(TAG, "Clearing archive states for " + ps.getPackageName());
+            }
+            ps.setArchiveState(/* archiveState= */ null, userId);
+        }
+        File iconsDir = getIconsDir(ps.getPackageName(), userId);
         if (!iconsDir.exists()) {
+            if (DEBUG) {
+                Slog.e(TAG, "Icons are already deleted at " + iconsDir.getAbsolutePath());
+            }
             return;
         }
         // TODO(b/319238030) Move this into installd.
         if (!FileUtils.deleteContentsAndDir(iconsDir)) {
-            Slog.e(TAG, "Failed to clean up archive files for " + packageName);
+            Slog.e(TAG, "Failed to clean up archive files for " + ps.getPackageName());
         } else {
             if (DEBUG) {
                 Slog.e(TAG, "Deleted icons at " + iconsDir.getAbsolutePath());
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 5792d86..ba90378 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -358,7 +358,7 @@
     /** Default byte size limit for app metadata */
     private static final long DEFAULT_APP_METADATA_BYTE_SIZE_LIMIT = 32000;
 
-    private static final int APP_METADATA_FILE_ACCESS_MODE = 0640;
+    static final int APP_METADATA_FILE_ACCESS_MODE = 0640;
 
     /**
      * Throws IllegalArgumentException if the {@link IntentSender} from an immutable
@@ -964,7 +964,7 @@
 
     private boolean isEmergencyInstallerEnabled(String packageName, Computer snapshot) {
         final PackageStateInternal ps = snapshot.getPackageStateInternal(packageName);
-        if (ps == null || ps.getPkg() == null || !ps.isSystem()) {
+        if (ps == null || ps.getPkg() == null) {
             return false;
         }
         String emergencyInstaller = ps.getPkg().getEmergencyInstaller();
@@ -1782,8 +1782,7 @@
     }
 
     private File getStagedAppMetadataFile() {
-        File file = new File(stageDir, APP_METADATA_FILE_NAME);
-        return file.exists() ? file : null;
+        return new File(stageDir, APP_METADATA_FILE_NAME);
     }
 
     private static boolean isAppMetadata(String name) {
@@ -1799,7 +1798,7 @@
         assertCallerIsOwnerOrRoot();
         synchronized (mLock) {
             assertPreparedAndNotCommittedOrDestroyedLocked("getAppMetadataFd");
-            if (getStagedAppMetadataFile() == null) {
+            if (!getStagedAppMetadataFile().exists()) {
                 return null;
             }
             try {
@@ -1813,12 +1812,12 @@
     @Override
     public void removeAppMetadata() {
         File file = getStagedAppMetadataFile();
-        if (file != null) {
+        if (file.exists()) {
             file.delete();
         }
     }
 
-    private static long getAppMetadataSizeLimit() {
+    static long getAppMetadataSizeLimit() {
         final long token = Binder.clearCallingIdentity();
         try {
             return DeviceConfig.getLong(NAMESPACE_PACKAGE_MANAGER_SERVICE,
@@ -2131,7 +2130,7 @@
         }
 
         File appMetadataFile = getStagedAppMetadataFile();
-        if (appMetadataFile != null) {
+        if (appMetadataFile.exists()) {
             long sizeLimit = getAppMetadataSizeLimit();
             if (appMetadataFile.length() > sizeLimit) {
                 appMetadataFile.delete();
@@ -3419,7 +3418,7 @@
 
         final List<ApkLite> addedFiles = getAddedApkLitesLocked();
         if (addedFiles.isEmpty()
-                && (removeSplitList.size() == 0 || getStagedAppMetadataFile() != null)) {
+                && (removeSplitList.size() == 0 || getStagedAppMetadataFile().exists())) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     TextUtils.formatSimple("Session: %d. No packages staged in %s", sessionId,
                           stageDir.getAbsolutePath()));
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index dadafd7..fe8030b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18,6 +18,8 @@
 import static android.Manifest.permission.MANAGE_DEVICE_ADMINS;
 import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
 import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.content.pm.PackageManager.APP_METADATA_SOURCE_APK;
+import static android.content.pm.PackageManager.APP_METADATA_SOURCE_UNKNOWN;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
@@ -596,7 +598,8 @@
     static final String RANDOM_DIR_PREFIX = "~~";
     static final char RANDOM_CODEPATH_PREFIX = '-';
 
-    static final String APP_METADATA_FILE_NAME = "app.metadata";
+    public static final String APP_METADATA_FILE_NAME = "app.metadata";
+    public static final String APP_METADATA_FILE_IN_APK_PATH = "assets/" + APP_METADATA_FILE_NAME;
 
     static final int DEFAULT_FILE_ACCESS_MODE = 0644;
 
@@ -721,7 +724,6 @@
 
     PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy;
 
-    @GuardedBy("mAvailableFeatures")
     private final ArrayMap<String, FeatureInfo> mAvailableFeatures;
 
     @Watched
@@ -1539,6 +1541,19 @@
             return;
         }
 
+        // Initialize all necessary settings for archival installation.
+        pkgSetting
+                // No package.
+                .setPkg(null)
+                // Mark for later restore.
+                .setPendingRestore(true);
+        for (int userId : userIds) {
+            // Unmark "installed" for all users.
+            pkgSetting
+                    .modifyUserState(userId)
+                    .setInstalled(false);
+        }
+
         String responsibleInstallerPackage = PackageArchiver.getResponsibleInstallerPackage(
                 pkgSetting);
         // TODO(b/278553670) Check if responsibleInstallerPackage supports unarchival.
@@ -1549,16 +1564,11 @@
         for (int userId : userIds) {
             var archiveState = mInstallerService.mPackageArchiver.createArchiveState(
                     archivePackage, userId, responsibleInstallerPackage);
-            if (archiveState == null) {
-                continue;
-            }
-            pkgSetting
-                    .setPkg(null)
-                    // This package was installed as archived. Need to mark it for later restore.
-                    .setPendingRestore(true)
+            if (archiveState != null) {
+                pkgSetting
                     .modifyUserState(userId)
-                    .setInstalled(false)
                     .setArchiveState(archiveState);
+            }
         }
     }
 
@@ -2983,13 +2993,11 @@
 
     public boolean hasSystemFeature(String name, int version) {
         // allow instant applications
-        synchronized (mAvailableFeatures) {
-            final FeatureInfo feat = mAvailableFeatures.get(name);
-            if (feat == null) {
-                return false;
-            } else {
-                return feat.version >= version;
-            }
+        final FeatureInfo feat = mAvailableFeatures.get(name);
+        if (feat == null) {
+            return false;
+        } else {
+            return feat.version >= version;
         }
     }
 
@@ -5230,15 +5238,30 @@
                         new PackageManager.NameNotFoundException(packageName));
             }
             String filePath = ps.getAppMetadataFilePath();
-            if (filePath != null) {
-                File file = new File(filePath);
-                try {
-                    return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
-                } catch (FileNotFoundException e) {
+            if (filePath == null) {
+                return null;
+            }
+            File file = new File(filePath);
+            if (Flags.aslInApkAppMetadataSource() && !file.exists()
+                    && ps.getAppMetadataSource() == APP_METADATA_SOURCE_APK) {
+                String apkPath = ps.getPkg().getSplits().get(0).getPath();
+                if (!PackageManagerServiceUtils.extractAppMetadataFromApk(apkPath, file)) {
+                    if (file.exists()) {
+                        file.delete();
+                    }
+                    synchronized (mLock) {
+                        PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
+                        pkgSetting.setAppMetadataFilePath(null);
+                        pkgSetting.setAppMetadataSource(APP_METADATA_SOURCE_UNKNOWN);
+                    }
                     return null;
                 }
             }
-            return null;
+            try {
+                return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
+            } catch (FileNotFoundException e) {
+                return null;
+            }
         }
 
         @android.annotation.EnforcePermission(android.Manifest.permission.GET_APP_METADATA)
@@ -5335,10 +5358,8 @@
         public @NonNull ParceledListSlice<FeatureInfo> getSystemAvailableFeatures() {
             // allow instant applications
             ArrayList<FeatureInfo> res;
-            synchronized (mAvailableFeatures) {
-                res = new ArrayList<>(mAvailableFeatures.size() + 1);
-                res.addAll(mAvailableFeatures.values());
-            }
+            res = new ArrayList<>(mAvailableFeatures.size() + 1);
+            res.addAll(mAvailableFeatures.values());
             final FeatureInfo fi = new FeatureInfo();
             fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version",
                     FeatureInfo.GL_ES_VERSION_UNDEFINED);
@@ -6542,9 +6563,7 @@
                     mOverlayConfigSignaturePackage,
                     mRecentsPackage);
             final ArrayMap<String, FeatureInfo> availableFeatures;
-            synchronized (mAvailableFeatures) {
-                availableFeatures = new ArrayMap<>(mAvailableFeatures);
-            }
+            availableFeatures = new ArrayMap<>(mAvailableFeatures);
             final ArraySet<String> protectedBroadcasts;
             synchronized (mProtectedBroadcasts) {
                 protectedBroadcasts = new ArraySet<>(mProtectedBroadcasts);
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 0a3dfc0..189a138 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -27,6 +27,9 @@
 import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
 import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH;
 import static com.android.server.LocalManagerRegistry.ManagerNotFoundException;
+import static com.android.server.pm.PackageInstallerSession.APP_METADATA_FILE_ACCESS_MODE;
+import static com.android.server.pm.PackageInstallerSession.getAppMetadataSizeLimit;
+import static com.android.server.pm.PackageManagerService.APP_METADATA_FILE_IN_APK_PATH;
 import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION;
 import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
 import static com.android.server.pm.PackageManagerService.DEBUG_INTENT_MATCHING;
@@ -142,6 +145,8 @@
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.zip.GZIPInputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
 
 /**
  * Class containing helper methods for the PackageManagerService.
@@ -1559,6 +1564,35 @@
         return initiatingPackageName == null || SHELL_PACKAGE_NAME.equals(initiatingPackageName);
     }
 
+    /**
+     * Extract the app.metadata file from apk.
+     */
+    public static boolean extractAppMetadataFromApk(String apkPath, File appMetadataFile) {
+        boolean found = false;
+        try (ZipInputStream zipInputStream =
+                     new ZipInputStream(new FileInputStream(new File(apkPath)))) {
+            ZipEntry zipEntry = null;
+            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
+                if (zipEntry.getName().equals(APP_METADATA_FILE_IN_APK_PATH)) {
+                    found = true;
+                    try (FileOutputStream out = new FileOutputStream(appMetadataFile)) {
+                        FileUtils.copy(zipInputStream, out);
+                    }
+                    if (appMetadataFile.length() > getAppMetadataSizeLimit()) {
+                        appMetadataFile.delete();
+                        return false;
+                    }
+                    Os.chmod(appMetadataFile.getAbsolutePath(), APP_METADATA_FILE_ACCESS_MODE);
+                    break;
+                }
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, e.getMessage());
+            return false;
+        }
+        return found;
+    }
+
     public static void linkFilesToOldDirs(@NonNull Installer installer,
                                            @NonNull String packageName,
                                            @NonNull File newPath,
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index 5e8778d..90d6adc 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -17,6 +17,7 @@
 package com.android.server.pm;
 
 import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
 import static android.content.pm.SigningDetails.CapabilityMergeRule.MERGE_RESTRICTED_CAPABILITY;
 
@@ -25,6 +26,7 @@
 import static com.android.server.pm.PackageManagerService.SCAN_DONT_KILL_APP;
 import static com.android.server.pm.PackageManagerService.TAG;
 
+import android.content.pm.Flags;
 import android.content.pm.PackageManager;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.SigningDetails;
@@ -36,6 +38,7 @@
 
 import com.android.internal.pm.parsing.pkg.ParsedPackage;
 import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.SystemConfig;
 import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.utils.WatchedLongSparseArray;
 
@@ -53,14 +56,17 @@
  * as install) led to the request.
  */
 final class ReconcilePackageUtils {
-    private static final boolean ALLOW_NON_PRELOADS_SYSTEM_SIGNATURE = Build.IS_DEBUGGABLE;
+    // TODO(b/308573259): with allow-list, we should be able to disallow such installs even in
+    // debuggable builds.
+    private static final boolean ALLOW_NON_PRELOADS_SYSTEM_SHAREDUIDS = Build.IS_DEBUGGABLE
+            || !Flags.restrictNonpreloadsSystemShareduids();
 
     public static List<ReconciledPackage> reconcilePackages(
             List<InstallRequest> installRequests,
             Map<String, AndroidPackage> allPackages,
             Map<String, Settings.VersionInfo> versionInfos,
             SharedLibrariesImpl sharedLibraries,
-            KeySetManagerService ksms, Settings settings)
+            KeySetManagerService ksms, Settings settings, SystemConfig systemConfig)
             throws ReconcileFailure {
         final List<ReconciledPackage> result = new ArrayList<>(installRequests.size());
 
@@ -187,11 +193,19 @@
                                     SigningDetails.CertCapabilities.PERMISSION)) {
                         Slog.d(TAG, "Non-preload app associated with system signature: "
                                 + signatureCheckPs.getPackageName());
-                        if (!ALLOW_NON_PRELOADS_SYSTEM_SIGNATURE) {
-                            throw new ReconcileFailure(
-                                    INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
-                                    "Non-preload app associated with system signature: "
-                                            + signatureCheckPs.getPackageName());
+                        if (sharedUserSetting != null && !ALLOW_NON_PRELOADS_SYSTEM_SHAREDUIDS) {
+                            // Check the allow-list.
+                            var allowList = systemConfig.getPackageToSharedUidAllowList();
+                            var sharedUidName = allowList.get(signatureCheckPs.getPackageName());
+                            if (sharedUidName == null
+                                    || !sharedUserSetting.name.equals(sharedUidName)) {
+                                var msg = "Non-preload app " + signatureCheckPs.getPackageName()
+                                        + " signed with platform signature and joining shared uid: "
+                                        + sharedUserSetting.name;
+                                Slog.e(TAG, msg + ", allowList: " + allowList);
+                                throw new ReconcileFailure(
+                                        INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID, msg);
+                            }
                         }
                     }
 
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index a600eea..211b754 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -520,7 +520,7 @@
         mShortcutRequestPinProcessor = new ShortcutRequestPinProcessor(this, mLock);
         mShortcutDumpFiles = new ShortcutDumpFiles(this);
         mIsAppSearchEnabled = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.SHORTCUT_APPSEARCH_INTEGRATION, true)
+                SystemUiDeviceConfigFlags.SHORTCUT_APPSEARCH_INTEGRATION, false)
                 && !injectIsLowRamDevice();
 
         if (onlyForPackageManagerApis) {
@@ -3795,6 +3795,7 @@
                 }
 
                 final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+                final boolean archival = intent.getBooleanExtra(Intent.EXTRA_ARCHIVAL, false);
 
                 switch (action) {
                     case Intent.ACTION_PACKAGE_ADDED:
@@ -3805,7 +3806,7 @@
                         }
                         break;
                     case Intent.ACTION_PACKAGE_REMOVED:
-                        if (!replacing) {
+                        if (!replacing || (replacing && archival)) {
                             handlePackageRemoved(packageName, userId);
                         }
                         break;
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 1c70af0..b18503d 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -596,7 +596,7 @@
         ai.requiredDisplayCategory = a.getRequiredDisplayCategory();
         ai.requireContentUriPermissionFromCaller = a.getRequireContentUriPermissionFromCaller();
         ai.setKnownActivityEmbeddingCerts(a.getKnownActivityEmbeddingCerts());
-        assignFieldsComponentInfoParsedMainComponent(ai, a, pkgSetting, userId);
+        assignFieldsComponentInfoParsedMainComponent(ai, a, pkgSetting, state, userId);
         return ai;
     }
 
@@ -659,7 +659,7 @@
             // Backwards compatibility, coerce to null if empty
             si.metaData = metaData.isEmpty() ? null : metaData;
         }
-        assignFieldsComponentInfoParsedMainComponent(si, s, pkgSetting, userId);
+        assignFieldsComponentInfoParsedMainComponent(si, s, pkgSetting, state, userId);
         return si;
     }
 
@@ -710,7 +710,7 @@
             pi.metaData = metaData.isEmpty() ? null : metaData;
         }
         pi.applicationInfo = applicationInfo;
-        assignFieldsComponentInfoParsedMainComponent(pi, p, pkgSetting, userId);
+        assignFieldsComponentInfoParsedMainComponent(pi, p, pkgSetting, state, userId);
         return pi;
     }
 
@@ -903,8 +903,13 @@
 
     private static void assignFieldsComponentInfoParsedMainComponent(
             @NonNull ComponentInfo info, @NonNull ParsedMainComponent component,
-            @NonNull PackageStateInternal pkgSetting, @UserIdInt int userId) {
+            @NonNull PackageStateInternal pkgSetting, @NonNull PackageUserStateInternal state,
+            @UserIdInt int userId) {
         assignFieldsComponentInfoParsedMainComponent(info, component);
+        // overwrite the enabled state with the current user state
+        info.enabled = PackageUserStateUtils.isEnabled(state, info.applicationInfo.enabled,
+                info.enabled, info.name, /* flags */ 0);
+
         Pair<CharSequence, Integer> labelAndIcon =
                 ParsedComponentStateUtils.getNonLocalizedLabelAndIcon(component, pkgSetting,
                         userId);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 47032ea..754b141 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -408,6 +408,9 @@
 
     /**
      * Gets the permission states for requested package, persistent device and user.
+     * <p>
+     * <strong>Note: </strong>Default device permissions are not inherited in this API. Returns the
+     * exact permission states for the requested device.
      *
      * @param packageName name of the package you are checking against
      * @param deviceId id of the persistent device you are checking against
diff --git a/services/core/java/com/android/server/policy/ModifierShortcutManager.java b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
index 539bb6b..3a79d0d 100644
--- a/services/core/java/com/android/server/policy/ModifierShortcutManager.java
+++ b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
@@ -17,6 +17,7 @@
 package com.android.server.policy;
 
 import android.annotation.SuppressLint;
+import android.app.role.RoleManager;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
@@ -45,6 +46,8 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * Manages quick launch shortcuts by:
@@ -52,8 +55,8 @@
  * <li> Returning a shortcut-matching intent to clients
  * <li> Returning particular kind of application intent by special key.
  */
-class ModifierShortcutManager {
-    private static final String TAG = "WindowManager";
+public class ModifierShortcutManager {
+    private static final String TAG = "ModifierShortcutManager";
 
     private static final String TAG_BOOKMARKS = "bookmarks";
     private static final String TAG_BOOKMARK = "bookmark";
@@ -63,9 +66,13 @@
     private static final String ATTRIBUTE_SHORTCUT = "shortcut";
     private static final String ATTRIBUTE_CATEGORY = "category";
     private static final String ATTRIBUTE_SHIFT = "shift";
+    private static final String ATTRIBUTE_ROLE = "role";
 
     private final SparseArray<Intent> mIntentShortcuts = new SparseArray<>();
     private final SparseArray<Intent> mShiftShortcuts = new SparseArray<>();
+    private final SparseArray<String> mRoleShortcuts = new SparseArray<String>();
+    private final SparseArray<String> mShiftRoleShortcuts = new SparseArray<String>();
+    private final Map<String, Intent> mRoleIntents = new HashMap<String, Intent>();
 
     private LongSparseArray<IShortcutService> mShortcutKeyServices = new LongSparseArray<>();
 
@@ -76,10 +83,12 @@
      * usage page.  We don't support quite that many yet...
      */
     static SparseArray<String> sApplicationLaunchKeyCategories;
+    static SparseArray<String> sApplicationLaunchKeyRoles;
     static {
+        sApplicationLaunchKeyRoles = new SparseArray<String>();
         sApplicationLaunchKeyCategories = new SparseArray<String>();
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_EXPLORER, Intent.CATEGORY_APP_BROWSER);
+        sApplicationLaunchKeyRoles.append(
+                KeyEvent.KEYCODE_EXPLORER, RoleManager.ROLE_BROWSER);
         sApplicationLaunchKeyCategories.append(
                 KeyEvent.KEYCODE_ENVELOPE, Intent.CATEGORY_APP_EMAIL);
         sApplicationLaunchKeyCategories.append(
@@ -92,14 +101,25 @@
                 KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR);
     }
 
+    public static final String EXTRA_ROLE =
+            "com.android.server.policy.ModifierShortcutManager.EXTRA_ROLE";
+
     private final Context mContext;
     private final Handler mHandler;
+    private final RoleManager mRoleManager;
+    private final PackageManager mPackageManager;
     private boolean mSearchKeyShortcutPending = false;
     private boolean mConsumeSearchKeyUp = true;
 
     ModifierShortcutManager(Context context, Handler handler) {
         mContext = context;
         mHandler = handler;
+        mPackageManager = mContext.getPackageManager();
+        mRoleManager = mContext.getSystemService(RoleManager.class);
+        mRoleManager.addOnRoleHoldersChangedListenerAsUser(mContext.getMainExecutor(),
+                (String roleName, UserHandle user) -> {
+                    mRoleIntents.remove(roleName);
+                }, UserHandle.ALL);
         loadShortcuts();
     }
 
@@ -141,14 +161,42 @@
             shortcutChar = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
             if (shortcutChar != 0) {
                 shortcutIntent = shortcutMap.get(shortcutChar);
+
+                if (shortcutIntent == null) {
+                    // Check for role based shortcut
+                    String role = isShiftOn ? mShiftRoleShortcuts.get(shortcutChar)
+                            : mRoleShortcuts.get(shortcutChar);
+                    if (role != null) {
+                        shortcutIntent = getRoleLaunchIntent(role);
+                    }
+                }
             }
         }
 
         return shortcutIntent;
     }
 
+    private Intent getRoleLaunchIntent(String role) {
+        Intent intent = mRoleIntents.get(role);
+        if (intent == null) {
+            if (mRoleManager.isRoleAvailable(role)) {
+                String rolePackage = mRoleManager.getDefaultApplication(role);
+                if (rolePackage != null) {
+                    intent = mPackageManager.getLaunchIntentForPackage(rolePackage);
+                    intent.putExtra(EXTRA_ROLE, role);
+                    mRoleIntents.put(role, intent);
+                } else {
+                    Log.w(TAG, "No default application for role " + role);
+                }
+            } else {
+                Log.w(TAG, "Role " + role + " is not available.");
+            }
+        }
+        return intent;
+    }
+
     private void loadShortcuts() {
-        PackageManager packageManager = mContext.getPackageManager();
+
         try {
             XmlResourceParser parser = mContext.getResources().getXml(
                     com.android.internal.R.xml.bookmarks);
@@ -170,29 +218,37 @@
                 String shortcutName = parser.getAttributeValue(null, ATTRIBUTE_SHORTCUT);
                 String categoryName = parser.getAttributeValue(null, ATTRIBUTE_CATEGORY);
                 String shiftName = parser.getAttributeValue(null, ATTRIBUTE_SHIFT);
+                String roleName = parser.getAttributeValue(null, ATTRIBUTE_ROLE);
 
                 if (TextUtils.isEmpty(shortcutName)) {
-                    Log.w(TAG, "Unable to get shortcut for: " + packageName + "/" + className);
+                    Log.w(TAG, "Shortcut required for bookmark with category=" + categoryName
+                            + " packageName=" + packageName + " className=" + className
+                            + " role=" + roleName + "shiftName=" + shiftName);
                     continue;
                 }
 
                 final int shortcutChar = shortcutName.charAt(0);
                 final boolean isShiftShortcut = (shiftName != null && shiftName.equals("true"));
-
                 final Intent intent;
                 if (packageName != null && className != null) {
+                    if (roleName != null || categoryName != null) {
+                        Log.w(TAG, "Cannot specify role or category when package and class"
+                                + " are present for bookmark packageName=" + packageName
+                                + " className=" + className + " shortcutChar=" + shortcutChar);
+                        continue;
+                    }
                     ComponentName componentName = new ComponentName(packageName, className);
                     try {
-                        packageManager.getActivityInfo(componentName,
+                        mPackageManager.getActivityInfo(componentName,
                                 PackageManager.MATCH_DIRECT_BOOT_AWARE
                                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                                         | PackageManager.MATCH_UNINSTALLED_PACKAGES);
                     } catch (PackageManager.NameNotFoundException e) {
-                        String[] packages = packageManager.canonicalToCurrentPackageNames(
+                        String[] packages = mPackageManager.canonicalToCurrentPackageNames(
                                 new String[] { packageName });
                         componentName = new ComponentName(packages[0], className);
                         try {
-                            packageManager.getActivityInfo(componentName,
+                            mPackageManager.getActivityInfo(componentName,
                                     PackageManager.MATCH_DIRECT_BOOT_AWARE
                                             | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                                             | PackageManager.MATCH_UNINSTALLED_PACKAGES);
@@ -207,10 +263,25 @@
                     intent.addCategory(Intent.CATEGORY_LAUNCHER);
                     intent.setComponent(componentName);
                 } else if (categoryName != null) {
+                    if (roleName != null) {
+                        Log.w(TAG, "Cannot specify role bookmark when category is present for"
+                                + " bookmark shortcutChar=" + shortcutChar
+                                + " category= " + categoryName);
+                        continue;
+                    }
                     intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, categoryName);
+                } else if (roleName != null) {
+                    // We can't resolve the role at the time of this file being parsed as the
+                    // device hasn't finished booting, so we will look it up lazily.
+                    if (isShiftShortcut) {
+                        mShiftRoleShortcuts.put(shortcutChar, roleName);
+                    } else {
+                        mRoleShortcuts.put(shortcutChar, roleName);
+                    }
+                    continue;
                 } else {
                     Log.w(TAG, "Unable to add bookmark for shortcut " + shortcutName
-                            + ": missing package/class or category attributes");
+                            + ": missing package/class, category or role attributes");
                     continue;
                 }
 
@@ -298,10 +369,17 @@
             // Invoke shortcuts using Meta.
             metaState &= ~KeyEvent.META_META_MASK;
         } else {
+            Intent intent = null;
             // Handle application launch keys.
+            String role = sApplicationLaunchKeyRoles.get(keyCode);
             String category = sApplicationLaunchKeyCategories.get(keyCode);
-            if (category != null) {
-                Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category);
+            if (role != null) {
+                intent = getRoleLaunchIntent(role);
+            } else if (category != null) {
+                intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category);
+            }
+
+            if (intent != null) {
                 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 try {
                     mContext.startActivityAsUser(intent, UserHandle.CURRENT);
@@ -309,7 +387,7 @@
                     Slog.w(TAG, "Dropping application launch key because "
                             + "the activity to which it is registered was not found: "
                             + "keyCode=" + KeyEvent.keyCodeToString(keyCode) + ","
-                            + " category=" + category);
+                            + " category=" + category + " role=" + role);
                 }
                 logKeyboardShortcut(keyEvent, KeyboardLogEvent.getLogEventFromIntent(intent));
                 return true;
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index f15646f..98499417 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -237,7 +237,7 @@
         mAppOpsCallback = new IAppOpsCallback.Stub() {
             public void opChanged(int op, int uid, @Nullable String packageName,
                     String persistentDeviceId) {
-                if (Objects.equals(persistentDeviceId,
+                if (!Objects.equals(persistentDeviceId,
                         VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT)) {
                     return;
                 }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 8781bf1..ec4b38b 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3504,8 +3504,8 @@
                 if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
                     StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
                     if (statusbar != null) {
-                        statusbar.goToFullscreenFromSplit();
-                        logKeyboardSystemsEvent(event, KeyboardLogEvent.SPLIT_SCREEN_NAVIGATION);
+                        statusbar.moveFocusedTaskToFullscreen(getTargetDisplayIdForKeyEvent(event));
+                        logKeyboardSystemsEvent(event, KeyboardLogEvent.MULTI_WINDOW_NAVIGATION);
                         return true;
                     }
                 }
@@ -3514,7 +3514,7 @@
                 if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
                     StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
                     if (statusbar != null) {
-                        statusbar.enterDesktop(event.getDisplayId());
+                        statusbar.enterDesktop(getTargetDisplayIdForKeyEvent(event));
                         logKeyboardSystemsEvent(event, KeyboardLogEvent.DESKTOP_MODE);
                         return true;
                     }
@@ -6410,7 +6410,7 @@
 
     private boolean performHapticFeedback(int effectId, boolean always, String reason) {
         return performHapticFeedback(Process.myUid(), mContext.getOpPackageName(),
-            effectId, always, reason);
+            effectId, always, reason, false /* fromIme */);
     }
 
     @Override
@@ -6420,7 +6420,7 @@
 
     @Override
     public boolean performHapticFeedback(int uid, String packageName, int effectId,
-            boolean always, String reason) {
+            boolean always, String reason, boolean fromIme) {
         if (!mVibrator.hasVibrator()) {
             return false;
         }
@@ -6431,7 +6431,7 @@
         }
         VibrationAttributes attrs =
                 mHapticFeedbackVibrationProvider.getVibrationAttributesForHapticFeedback(
-                        effectId, /* bypassVibrationIntensitySetting= */ always);
+                        effectId, /* bypassVibrationIntensitySetting= */ always, fromIme);
         VibratorFrameworkStatsLogger.logPerformHapticsFeedbackIfKeyboard(uid, effectId);
         mVibrator.vibrate(uid, packageName, effect, reason, attrs);
         return true;
@@ -6951,4 +6951,18 @@
                     == PERMISSION_GRANTED;
         }
     }
+
+    private int getTargetDisplayIdForKeyEvent(KeyEvent event) {
+        int displayId = event.getDisplayId();
+
+        if (displayId == INVALID_DISPLAY) {
+            displayId = mTopFocusedDisplayId;
+        }
+
+        if (displayId == INVALID_DISPLAY) {
+            return DEFAULT_DISPLAY;
+        } else {
+            return displayId;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
index 32a21c5..cebf7fb 100644
--- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
+++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
@@ -21,7 +21,6 @@
 import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
 import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
 import static android.app.AppOpsManager.OP_NONE;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
@@ -148,7 +147,7 @@
                             pkg.hasPreserveLegacyExternalStorage();
                     targetSDK = getMinimumTargetSDK(context, appInfo, user);
 
-                    shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
+                    shouldApplyRestriction = !isWhiteListed;
                     isForcedScopedStorage = sForcedScopedStorageAppWhitelist
                             .contains(appInfo.packageName);
                 } else {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 2174fd6..5956594 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -1072,7 +1072,7 @@
      * Call from application to perform haptic feedback on its window.
      */
     public boolean performHapticFeedback(int uid, String packageName, int effectId,
-            boolean always, String reason);
+            boolean always, String reason, boolean fromIme);
 
     /**
      * Called when we have started keeping the screen on because a window
diff --git a/services/core/java/com/android/server/power/Android.bp b/services/core/java/com/android/server/power/Android.bp
index 607d435..863ff76 100644
--- a/services/core/java/com/android/server/power/Android.bp
+++ b/services/core/java/com/android/server/power/Android.bp
@@ -9,4 +9,5 @@
 java_aconfig_library {
     name: "backstage_power_flags_lib",
     aconfig_declarations: "backstage_power_flags",
+    sdk_version: "system_current",
 }
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index b22e37b..c8cb92b 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -167,6 +167,9 @@
     /** Config flag to track if battery saver's sticky behaviour is disabled. */
     private final boolean mBatterySaverStickyBehaviourDisabled;
 
+    /** Config flag to track if "Battery Saver turned off" notification is enabled. */
+    private final boolean mBatterySaverTurnedOffNotificationEnabled;
+
     /**
      * Whether or not to end sticky battery saver upon reaching a level specified by
      * {@link #mSettingBatterySaverStickyAutoDisableThreshold}.
@@ -250,6 +253,8 @@
 
         mBatterySaverStickyBehaviourDisabled = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled);
+        mBatterySaverTurnedOffNotificationEnabled = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_batterySaverTurnedOffNotificationEnabled);
         mDynamicPowerSavingsDefaultDisableThreshold = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold);
     }
@@ -858,6 +863,9 @@
 
     @VisibleForTesting
     void triggerStickyDisabledNotification() {
+        if (!mBatterySaverTurnedOffNotificationEnabled) {
+            return;
+        }
         // The current lock is the PowerManager lock, which sits very low in the service lock
         // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock.
         runOnBgThread(() -> {
@@ -997,6 +1005,8 @@
             ipw.println(mSettingBatterySaverTriggerThreshold);
             ipw.print("mBatterySaverStickyBehaviourDisabled=");
             ipw.println(mBatterySaverStickyBehaviourDisabled);
+            ipw.print("mBatterySaverTurnedOffNotificationEnabled=");
+            ipw.println(mBatterySaverTurnedOffNotificationEnabled);
 
             ipw.print("mDynamicPowerSavingsDefaultDisableThreshold=");
             ipw.println(mDynamicPowerSavingsDefaultDisableThreshold);
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsSpan.java b/services/core/java/com/android/server/power/stats/PowerStatsSpan.java
index 3b260ca..4df919d 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsSpan.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsSpan.java
@@ -57,7 +57,7 @@
      * {@link #isCompatibleXmlFormat} to return true for all legacy versions
      * that are compatible with the new one.
      */
-    private static final int VERSION = 1;
+    private static final int VERSION = 2;
 
     private static final String XML_TAG_METADATA = "metadata";
     private static final String XML_ATTR_ID = "id";
diff --git a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
index bb5a697..7ddb61e 100644
--- a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
+++ b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
@@ -68,12 +68,14 @@
     private final ComponentName mComponentName;
 
     RemoteSpeechRecognitionService(
-            Context context, ComponentName serviceName, int userId, int callingUid) {
+            Context context,
+            ComponentName serviceName,
+            int userId,
+            int callingUid,
+            boolean isPrivileged) {
         super(context,
                 new Intent(RecognitionService.SERVICE_INTERFACE).setComponent(serviceName),
-                Context.BIND_AUTO_CREATE
-                        | Context.BIND_FOREGROUND_SERVICE
-                        | Context.BIND_INCLUDE_CAPABILITIES,
+                getBindingFlags(isPrivileged),
                 userId,
                 IRecognitionService.Stub::asInterface);
 
@@ -85,6 +87,14 @@
         }
     }
 
+    private static int getBindingFlags(boolean isPrivileged) {
+        int bindingFlags = Context.BIND_AUTO_CREATE;
+        if (isPrivileged) {
+            bindingFlags |= Context.BIND_INCLUDE_CAPABILITIES | Context.BIND_FOREGROUND_SERVICE;
+        }
+        return bindingFlags;
+    }
+
     ComponentName getServiceComponentName() {
         return mComponentName;
     }
diff --git a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
index 8e9c889..808504f 100644
--- a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
@@ -23,6 +23,7 @@
 import android.content.AttributionSource;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
@@ -31,6 +32,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.permission.PermissionManager;
+import android.provider.Settings;
 import android.speech.IModelDownloadListener;
 import android.speech.IRecognitionListener;
 import android.speech.IRecognitionService;
@@ -311,9 +313,22 @@
                 return null;
             }
 
+            final boolean isPrivileged;
+            if (serviceComponent == null) {
+                isPrivileged = false;
+            } else {
+                // Only certain privileged recognition service can obtain process capabilities
+                // from persistent process to hold while-in-use permission in the background.
+                isPrivileged = checkPrivilege(serviceComponent);
+            }
+
             RemoteSpeechRecognitionService service =
                     new RemoteSpeechRecognitionService(
-                            getContext(), serviceComponent, getUserId(), callingUid);
+                            getContext(),
+                            serviceComponent,
+                            getUserId(),
+                            callingUid,
+                            isPrivileged);
 
             Set<RemoteSpeechRecognitionService> valuesByCaller =
                     mRemoteServicesByUid.computeIfAbsent(callingUid, key -> new HashSet<>());
@@ -328,6 +343,53 @@
         }
     }
 
+    /**
+     * Checks if the given service component should have privileged binding flags when created. Only
+     * a service component that matches with any of the following condition would be granted:
+     *
+     * <ul>
+     *     <li>A default recognition service component.</li>
+     *     <li>An on-device recognition service component.</li>
+     *     <li>A pre-installed recognition service component.</li>
+     * </ul>
+     */
+    @GuardedBy("mLock")
+    private boolean checkPrivilege(@NonNull ComponentName serviceComponent) {
+        final ComponentName defaultComponent = getDefaultRecognitionServiceComponent();
+        final ComponentName onDeviceComponent = getOnDeviceComponentNameLocked();
+        final boolean preinstalled = isPreinstalledApp(serviceComponent);
+        return serviceComponent.equals(defaultComponent)
+                || serviceComponent.equals(onDeviceComponent)
+                || preinstalled;
+    }
+
+    private boolean isPreinstalledApp(@NonNull ComponentName serviceComponent) {
+        PackageManager pm = getContext().getPackageManager();
+        if (pm == null) {
+            return false;
+        }
+
+        try {
+            ApplicationInfo info = pm.getApplicationInfoAsUser(serviceComponent.getPackageName(),
+                    PackageManager.MATCH_SYSTEM_ONLY, getUserId());
+            return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+    }
+
+    @Nullable
+    private ComponentName getDefaultRecognitionServiceComponent() {
+        String componentName = Settings.Secure.getStringForUser(
+                getContext().getContentResolver(),
+                Settings.Secure.VOICE_RECOGNITION_SERVICE,
+                getUserId());
+        if (componentName == null) {
+            return null;
+        }
+        return ComponentName.unflattenFromString(componentName);
+    }
+
     private boolean componentMapsToRecognitionService(@NonNull ComponentName serviceComponent) {
         List<ResolveInfo> resolveInfos;
 
diff --git a/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java b/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java
index b0dcf95..881583a 100644
--- a/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java
+++ b/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java
@@ -282,10 +282,7 @@
             Slog.d(TAG,
                     "pullDataBytesTransferLocked() done. results count " + pulledData.size());
         }
-        if (!pulledData.isEmpty()) {
-            return StatsManager.PULL_SUCCESS;
-        }
-        return StatsManager.PULL_SKIP;
+        return StatsManager.PULL_SUCCESS;
     }
 
     private static boolean isEmpty(NetworkStats stats) {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 3c6baa8..14e0ce1 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -224,9 +224,11 @@
     void showRearDisplayDialog(int currentBaseState);
 
     /**
-     * Called when requested to go to fullscreen from the active split app.
+     * Called when requested to go to fullscreen from the focused app.
+     *
+     * @param displayId of the current display.
      */
-    void goToFullscreenFromSplit();
+    void moveFocusedTaskToFullscreen(int displayId);
 
     /**
      * Enters stage split from a current running app.
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 14c38bd..0b48a75 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -810,11 +810,11 @@
         }
 
         @Override
-        public void goToFullscreenFromSplit() {
+        public void moveFocusedTaskToFullscreen(int displayId) {
             IStatusBar bar = mBar;
             if (bar != null) {
                 try {
-                    bar.goToFullscreenFromSplit();
+                    bar.moveFocusedTaskToFullscreen(displayId);
                 } catch (RemoteException ex) { }
             }
         }
diff --git a/services/core/java/com/android/server/utils/AnrTimer.java b/services/core/java/com/android/server/utils/AnrTimer.java
index 743005a..b7d8cfc 100644
--- a/services/core/java/com/android/server/utils/AnrTimer.java
+++ b/services/core/java/com/android/server/utils/AnrTimer.java
@@ -767,7 +767,7 @@
      * Return true if the native timers are supported.  Native timers are supported if the method
      * nativeAnrTimerSupported() can be executed and it returns true.
      */
-    private static boolean nativeTimersSupported() {
+    public static boolean nativeTimersSupported() {
         try {
             return nativeAnrTimerSupported();
         } catch (java.lang.UnsatisfiedLinkError e) {
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index 17f5e95..7206c03 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -164,7 +164,6 @@
         registerCarrierPrivilegesCallbacks();
     }
 
-    // TODO(b/221306368): Refactor with the new onCarrierServiceChange in the new CPCallback
     private void registerCarrierPrivilegesCallbacks() {
         final HandlerExecutor executor = new HandlerExecutor(mHandler);
         final int modemCount = mTelephonyManager.getActiveModemCount();
diff --git a/services/core/java/com/android/server/vibrator/GroupedAggregatedLogRecords.java b/services/core/java/com/android/server/vibrator/GroupedAggregatedLogRecords.java
new file mode 100644
index 0000000..7ee2901
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/GroupedAggregatedLogRecords.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import android.os.SystemClock;
+import android.util.IndentingPrintWriter;
+import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
+
+import java.util.ArrayDeque;
+
+/**
+ * A generic grouped list of aggregated log records to be printed in dumpsys.
+ *
+ * <p>This can be used to dump history of operations or requests to the vibrator services, e.g.
+ * vibration requests grouped by usage or vibration parameters sent to the vibrator control service.
+ *
+ * @param <T> The type of log entries aggregated in this record.
+ */
+abstract class GroupedAggregatedLogRecords<T extends GroupedAggregatedLogRecords.SingleLogRecord> {
+    private final SparseArray<ArrayDeque<AggregatedLogRecord<T>>> mGroupedRecords;
+    private final int mSizeLimit;
+    private final int mAggregationTimeLimitMs;
+
+    GroupedAggregatedLogRecords(int sizeLimit, int aggregationTimeLimitMs) {
+        mGroupedRecords = new SparseArray<>();
+        mSizeLimit = sizeLimit;
+        mAggregationTimeLimitMs = aggregationTimeLimitMs;
+    }
+
+    /** Prints a header to identify the group to be logged. */
+    abstract void dumpGroupHeader(IndentingPrintWriter pw, int groupKey);
+
+    /** Returns the {@link ProtoOutputStream} repeated field id to log records of this group. */
+    abstract long findGroupKeyProtoFieldId(int groupKey);
+
+    /**
+     * Adds given entry to this record list, dropping the oldest record if size limit was reached
+     * for its group.
+     *
+     * @param record The new {@link SingleLogRecord} to be recorded.
+     * @return The oldest {@link AggregatedLogRecord} entry being dropped from the group list if
+     * it's full, null otherwise.
+     */
+    final synchronized AggregatedLogRecord<T> add(T record) {
+        int groupKey = record.getGroupKey();
+        if (!mGroupedRecords.contains(groupKey)) {
+            mGroupedRecords.put(groupKey, new ArrayDeque<>(mSizeLimit));
+        }
+        ArrayDeque<AggregatedLogRecord<T>> records = mGroupedRecords.get(groupKey);
+        if (mAggregationTimeLimitMs > 0 && !records.isEmpty()) {
+            AggregatedLogRecord<T> lastAggregatedRecord = records.getLast();
+            if (lastAggregatedRecord.mayAggregate(record, mAggregationTimeLimitMs)) {
+                lastAggregatedRecord.record(record);
+                return null;
+            }
+        }
+        AggregatedLogRecord<T> removedRecord = null;
+        if (records.size() >= mSizeLimit) {
+            removedRecord = records.removeFirst();
+        }
+        records.addLast(new AggregatedLogRecord<>(record));
+        return removedRecord;
+    }
+
+    final synchronized void dump(IndentingPrintWriter pw) {
+        for (int i = 0; i < mGroupedRecords.size(); i++) {
+            dumpGroupHeader(pw, mGroupedRecords.keyAt(i));
+            pw.increaseIndent();
+            for (AggregatedLogRecord<T> records : mGroupedRecords.valueAt(i)) {
+                records.dump(pw);
+            }
+            pw.decreaseIndent();
+            pw.println();
+        }
+    }
+
+    final synchronized void dump(ProtoOutputStream proto) {
+        for (int i = 0; i < mGroupedRecords.size(); i++) {
+            long fieldId = findGroupKeyProtoFieldId(mGroupedRecords.keyAt(i));
+            for (AggregatedLogRecord<T> records : mGroupedRecords.valueAt(i)) {
+                records.dump(proto, fieldId);
+            }
+        }
+    }
+
+    /**
+     * Represents an aggregation of log record entries that can be printed in a compact manner.
+     *
+     * <p>The aggregation is controlled by a time limit on the difference between the creation time
+     * of two consecutive entries that {@link SingleLogRecord#mayAggregate}.
+     *
+     * @param <T> The type of log entries aggregated in this record.
+     */
+    static final class AggregatedLogRecord<T extends SingleLogRecord> {
+        private final T mFirst;
+        private T mLatest;
+        private int mCount;
+
+        AggregatedLogRecord(T record) {
+            mLatest = mFirst = record;
+            mCount = 1;
+        }
+
+        T getLatest() {
+            return mLatest;
+        }
+
+        synchronized boolean mayAggregate(T record, long timeLimitMs) {
+            long timeDeltaMs = Math.abs(mLatest.getCreateUptimeMs() - record.getCreateUptimeMs());
+            return mLatest.mayAggregate(record) && timeDeltaMs < timeLimitMs;
+        }
+
+        synchronized void record(T record) {
+            mLatest = record;
+            mCount++;
+        }
+
+        synchronized void dump(IndentingPrintWriter pw) {
+            mFirst.dump(pw);
+            if (mCount == 1) {
+                return;
+            }
+            if (mCount > 2) {
+                pw.println("-> Skipping " + (mCount - 2) + " aggregated entries, latest:");
+            }
+            mLatest.dump(pw);
+        }
+
+        synchronized void dump(ProtoOutputStream proto, long fieldId) {
+            mFirst.dump(proto, fieldId);
+            if (mCount > 1) {
+                mLatest.dump(proto, fieldId);
+            }
+        }
+    }
+
+    /**
+     * Represents a single log entry that can be grouped and aggregated for compact logging.
+     *
+     * <p>Entries are first grouped by an integer group key, and then aggregated with consecutive
+     * entries of same group within a limited timespan.
+     */
+    interface SingleLogRecord {
+
+        /** The group identifier for this record (e.g. vibration usage). */
+        int getGroupKey();
+
+        /**
+         * The timestamp in millis that should be used for aggregation of close entries.
+         *
+         * <p>Should be {@link SystemClock#uptimeMillis()} to be used for calculations.
+         */
+        long getCreateUptimeMs();
+
+        /**
+         * Returns true if this record can be aggregated with the given one (e.g. the represent the
+         * same vibration request from the same process client).
+         */
+        boolean mayAggregate(SingleLogRecord record);
+
+        /** Writes this record into given {@link IndentingPrintWriter}. */
+        void dump(IndentingPrintWriter pw);
+
+        /** Writes this record into given {@link ProtoOutputStream} field. */
+        void dump(ProtoOutputStream proto, long fieldId);
+    }
+}
diff --git a/services/core/java/com/android/server/vibrator/HalVibration.java b/services/core/java/com/android/server/vibrator/HalVibration.java
index 70e2e27..8f755f4 100644
--- a/services/core/java/com/android/server/vibrator/HalVibration.java
+++ b/services/core/java/com/android/server/vibrator/HalVibration.java
@@ -54,12 +54,18 @@
     /** Vibration status. */
     private Vibration.Status mStatus;
 
+    /** Reported scale values applied to the vibration effects. */
+    private int mScaleLevel;
+    private float mAdaptiveScale;
+
     HalVibration(@NonNull IBinder token, @NonNull CombinedVibration effect,
             @NonNull CallerInfo callerInfo) {
         super(token, callerInfo);
         mOriginalEffect = effect;
         mEffectToPlay = effect;
         mStatus = Vibration.Status.RUNNING;
+        mScaleLevel = VibrationScaler.SCALE_NONE;
+        mAdaptiveScale = VibrationScaler.ADAPTIVE_SCALE_NONE;
     }
 
     /**
@@ -119,20 +125,24 @@
     }
 
     /**
-     * Scales the {@link #getEffectToPlay()} and each fallback effect with a scaling transformation.
-     *
-     * @param scaler A {@link VibrationEffect.Transformation<Integer>} that takes one of the
-     *               {@code VibrationAttributes.USAGE_*} as the modifier to scale the effect
-     *               based on the user settings.
+     * Scales the {@link #getEffectToPlay()} and each fallback effect based on the vibration usage.
      */
-    public void scaleEffects(VibrationEffect.Transformation<Integer> scaler) {
+    public void scaleEffects(VibrationScaler scaler) {
         int vibrationUsage = callerInfo.attrs.getUsage();
-        CombinedVibration newEffect = mEffectToPlay.transform(scaler, vibrationUsage);
+
+        // Save scale values for debugging purposes.
+        mScaleLevel = scaler.getScaleLevel(vibrationUsage);
+        mAdaptiveScale = scaler.getAdaptiveHapticsScale(vibrationUsage);
+
+        // Scale all VibrationEffect instances in given CombinedVibration.
+        CombinedVibration newEffect = mEffectToPlay.transform(scaler::scale, vibrationUsage);
         if (!Objects.equals(mEffectToPlay, newEffect)) {
             mEffectToPlay = newEffect;
         }
+
+        // Scale all fallback VibrationEffect instances that can be used by VibrationThread.
         for (int i = 0; i < mFallbacks.size(); i++) {
-            mFallbacks.setValueAt(i, scaler.transform(mFallbacks.valueAt(i), vibrationUsage));
+            mFallbacks.setValueAt(i, scaler.scale(mFallbacks.valueAt(i), vibrationUsage));
         }
     }
 
@@ -171,7 +181,7 @@
         CombinedVibration originalEffect =
                 Objects.equals(mOriginalEffect, mEffectToPlay) ? null : mOriginalEffect;
         return new Vibration.DebugInfo(mStatus, stats, mEffectToPlay, originalEffect,
-                /* scale= */ 0, callerInfo);
+                mScaleLevel, mAdaptiveScale, callerInfo);
     }
 
     /** Return {@link VibrationStats.StatsInfo} with read-only metrics about this vibration. */
diff --git a/services/core/java/com/android/server/vibrator/HapticFeedbackCustomization.java b/services/core/java/com/android/server/vibrator/HapticFeedbackCustomization.java
index a346216..9756094 100644
--- a/services/core/java/com/android/server/vibrator/HapticFeedbackCustomization.java
+++ b/services/core/java/com/android/server/vibrator/HapticFeedbackCustomization.java
@@ -19,8 +19,8 @@
 import android.annotation.Nullable;
 import android.content.res.Resources;
 import android.os.VibrationEffect;
-import android.os.vibrator.Flags;
 import android.os.VibratorInfo;
+import android.os.vibrator.Flags;
 import android.os.vibrator.persistence.ParsedVibration;
 import android.os.vibrator.persistence.VibrationXmlParser;
 import android.text.TextUtils;
@@ -73,8 +73,6 @@
  *
  * <p>After a successful parsing of the customization XML file, it returns a {@link SparseArray}
  * that maps each customized haptic feedback effect ID to its respective {@link VibrationEffect}.
- *
- * @hide
  */
 final class HapticFeedbackCustomization {
     private static final String TAG = "HapticFeedbackCustomization";
@@ -104,8 +102,6 @@
      * @throws {@link IOException} if an IO error occurs while parsing the customization XML.
      * @throws {@link CustomizationParserException} for any non-IO error that occurs when parsing
      *      the XML, like an invalid XML content or an invalid haptic feedback constant.
-     *
-     * @hide
      */
     @Nullable
     static SparseArray<VibrationEffect> loadVibrations(Resources res, VibratorInfo vibratorInfo)
@@ -202,8 +198,6 @@
 
     /**
      * Represents an error while parsing a haptic feedback customization XML.
-     *
-     * @hide
      */
     static final class CustomizationParserException extends Exception {
         private CustomizationParserException(String message) {
diff --git a/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java b/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
index 519acec..96f045d 100644
--- a/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
+++ b/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
@@ -34,8 +34,6 @@
 
 /**
  * Provides the {@link VibrationEffect} and {@link VibrationAttributes} for haptic feedback.
- *
- * @hide
  */
 public final class HapticFeedbackVibrationProvider {
     private static final String TAG = "HapticFeedbackVibrationProvider";
@@ -58,17 +56,14 @@
 
     private float mKeyboardVibrationFixedAmplitude;
 
-    /** @hide */
     public HapticFeedbackVibrationProvider(Resources res, Vibrator vibrator) {
         this(res, vibrator.getInfo());
     }
 
-    /** @hide */
     public HapticFeedbackVibrationProvider(Resources res, VibratorInfo vibratorInfo) {
         this(res, vibratorInfo, loadHapticCustomizations(res, vibratorInfo));
     }
 
-    /** @hide */
     @VisibleForTesting HapticFeedbackVibrationProvider(
             Resources res,
             VibratorInfo vibratorInfo,
@@ -190,10 +185,11 @@
      *      to get.
      * @param bypassVibrationIntensitySetting {@code true} if the returned attribute should bypass
      *      vibration intensity settings. {@code false} otherwise.
+     * @param fromIme the haptic feedback is performed from an IME.
      * @return the {@link VibrationAttributes} that should be used for the provided haptic feedback.
      */
     public VibrationAttributes getVibrationAttributesForHapticFeedback(
-            int effectId, boolean bypassVibrationIntensitySetting) {
+            int effectId, boolean bypassVibrationIntensitySetting, boolean fromIme) {
         VibrationAttributes attrs;
         switch (effectId) {
             case HapticFeedbackConstants.EDGE_SQUEEZE:
@@ -209,7 +205,7 @@
                 break;
             case HapticFeedbackConstants.KEYBOARD_TAP:
             case HapticFeedbackConstants.KEYBOARD_RELEASE:
-                attrs = createKeyboardVibrationAttributes();
+                attrs = createKeyboardVibrationAttributes(fromIme);
                 break;
             default:
                 attrs = TOUCH_VIBRATION_ATTRIBUTES;
@@ -222,7 +218,7 @@
         if (shouldBypassInterruptionPolicy(effectId)) {
             flags |= VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
         }
-        if (shouldBypassIntensityScale(effectId)) {
+        if (shouldBypassIntensityScale(effectId, fromIme)) {
             flags |= VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE;
         }
 
@@ -337,9 +333,9 @@
                 /* fallbackForPredefinedEffect= */ predefinedEffectFallback);
     }
 
-    private boolean shouldBypassIntensityScale(int effectId) {
-        if (!Flags.keyboardCategoryEnabled() || mKeyboardVibrationFixedAmplitude < 0) {
-            // shouldn't bypass if not support keyboard category or no fixed amplitude
+    private boolean shouldBypassIntensityScale(int effectId, boolean isIme) {
+        if (!Flags.keyboardCategoryEnabled() || mKeyboardVibrationFixedAmplitude < 0 || !isIme) {
+            // Shouldn't bypass if not support keyboard category, no fixed amplitude or not an IME.
             return false;
         }
         switch (effectId) {
@@ -353,8 +349,9 @@
         return false;
     }
 
-    private static VibrationAttributes createKeyboardVibrationAttributes() {
-        if (!Flags.keyboardCategoryEnabled()) {
+    private VibrationAttributes createKeyboardVibrationAttributes(boolean fromIme) {
+        // Use touch attribute when the keyboard category is disable or it's not from an IME.
+        if (!Flags.keyboardCategoryEnabled() || !fromIme) {
             return TOUCH_VIBRATION_ATTRIBUTES;
         }
 
diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java
index b2e808a..b490f57 100644
--- a/services/core/java/com/android/server/vibrator/Vibration.java
+++ b/services/core/java/com/android/server/vibrator/Vibration.java
@@ -218,12 +218,13 @@
         private final long mDurationMs;
         @Nullable
         private final CombinedVibration mOriginalEffect;
-        private final float mScale;
+        private final int mScaleLevel;
+        private final float mAdaptiveScale;
         private final Status mStatus;
 
         DebugInfo(Status status, VibrationStats stats, @Nullable CombinedVibration playedEffect,
-                @Nullable CombinedVibration originalEffect, float scale,
-                @NonNull CallerInfo callerInfo) {
+                @Nullable CombinedVibration originalEffect, int scaleLevel,
+                float adaptiveScale, @NonNull CallerInfo callerInfo) {
             Objects.requireNonNull(callerInfo);
             mCreateTime = stats.getCreateTimeDebug();
             mStartTime = stats.getStartTimeDebug();
@@ -231,7 +232,8 @@
             mDurationMs = stats.getDurationDebug();
             mPlayedEffect = playedEffect;
             mOriginalEffect = originalEffect;
-            mScale = scale;
+            mScaleLevel = scaleLevel;
+            mAdaptiveScale = adaptiveScale;
             mCallerInfo = callerInfo;
             mStatus = status;
         }
@@ -246,7 +248,8 @@
                     + ", status: " + mStatus.name().toLowerCase(Locale.ROOT)
                     + ", playedEffect: " + mPlayedEffect
                     + ", originalEffect: " + mOriginalEffect
-                    + ", scale: " + String.format(Locale.ROOT, "%.2f", mScale)
+                    + ", scaleLevel: " + VibrationScaler.scaleLevelToString(mScaleLevel)
+                    + ", adaptiveScale: " + String.format(Locale.ROOT, "%.2f", mAdaptiveScale)
                     + ", callerInfo: " + mCallerInfo;
         }
 
@@ -259,26 +262,39 @@
         void dumpCompact(IndentingPrintWriter pw) {
             boolean isExternalVibration = mPlayedEffect == null;
             String timingsStr = String.format(Locale.ROOT,
-                    "%s | %8s | %20s | duration: %5dms | start: %12s | end: %10s",
+                    "%s | %8s | %20s | duration: %5dms | start: %12s | end: %12s",
                     DEBUG_DATE_TIME_FORMAT.format(new Date(mCreateTime)),
                     isExternalVibration ? "external" : "effect",
                     mStatus.name().toLowerCase(Locale.ROOT),
                     mDurationMs,
                     mStartTime == 0 ? "" : DEBUG_TIME_FORMAT.format(new Date(mStartTime)),
                     mEndTime == 0 ? "" : DEBUG_TIME_FORMAT.format(new Date(mEndTime)));
-            String callerInfoStr = String.format(Locale.ROOT,
-                    " | %s (uid=%d, deviceId=%d) | usage: %s (audio=%s) | flags: %s | reason: %s",
-                    mCallerInfo.opPkg, mCallerInfo.uid, mCallerInfo.deviceId,
-                    mCallerInfo.attrs.usageToString(),
-                    AudioAttributes.usageToString(mCallerInfo.attrs.getAudioUsage()),
+            String paramStr = String.format(Locale.ROOT,
+                    " | scale: %8s (adaptive=%.2f) | flags: %4s | usage: %s",
+                    VibrationScaler.scaleLevelToString(mScaleLevel), mAdaptiveScale,
                     Long.toBinaryString(mCallerInfo.attrs.getFlags()),
-                    mCallerInfo.reason);
+                    mCallerInfo.attrs.usageToString());
+            // Optional, most vibrations have category unknown so skip them to simplify the logs
+            String categoryStr =
+                    mCallerInfo.attrs.getCategory() != VibrationAttributes.CATEGORY_UNKNOWN
+                            ? " | category=" + VibrationAttributes.categoryToString(
+                            mCallerInfo.attrs.getCategory())
+                            : "";
+            // Optional, most vibrations should not be defined via AudioAttributes
+            // so skip them to simplify the logs
+            String audioUsageStr =
+                    mCallerInfo.attrs.getOriginalAudioUsage() != AudioAttributes.USAGE_UNKNOWN
+                            ? " | audioUsage=" + AudioAttributes.usageToString(
+                            mCallerInfo.attrs.getOriginalAudioUsage())
+                            : "";
+            String callerStr = String.format(Locale.ROOT,
+                    " | %s (uid=%d, deviceId=%d) | reason: %s",
+                    mCallerInfo.opPkg, mCallerInfo.uid, mCallerInfo.deviceId, mCallerInfo.reason);
             String effectStr = String.format(Locale.ROOT,
-                    " | played: %s | original: %s | scale: %.2f",
+                    " | played: %s | original: %s",
                     mPlayedEffect == null ? null : mPlayedEffect.toDebugString(),
-                    mOriginalEffect == null ? null : mOriginalEffect.toDebugString(),
-                    mScale);
-            pw.println(timingsStr + callerInfoStr + effectStr);
+                    mOriginalEffect == null ? null : mOriginalEffect.toDebugString());
+            pw.println(timingsStr + paramStr + categoryStr + audioUsageStr + callerStr + effectStr);
         }
 
         /** Write this info into given {@link PrintWriter}. */
@@ -293,7 +309,8 @@
                     + (mEndTime == 0 ? null : DEBUG_DATE_TIME_FORMAT.format(new Date(mEndTime))));
             pw.println("playedEffect = " + mPlayedEffect);
             pw.println("originalEffect = " + mOriginalEffect);
-            pw.println("scale = " + String.format(Locale.ROOT, "%.2f", mScale));
+            pw.println("scale = " + VibrationScaler.scaleLevelToString(mScaleLevel));
+            pw.println("adaptiveScale = " + String.format(Locale.ROOT, "%.2f", mAdaptiveScale));
             pw.println("callerInfo = " + mCallerInfo);
             pw.decreaseIndent();
         }
@@ -310,6 +327,7 @@
             final VibrationAttributes attrs = mCallerInfo.attrs;
             proto.write(VibrationAttributesProto.USAGE, attrs.getUsage());
             proto.write(VibrationAttributesProto.AUDIO_USAGE, attrs.getAudioUsage());
+            proto.write(VibrationAttributesProto.CATEGORY, attrs.getCategory());
             proto.write(VibrationAttributesProto.FLAGS, attrs.getFlags());
             proto.end(attrsToken);
 
diff --git a/services/core/java/com/android/server/vibrator/VibrationScaler.java b/services/core/java/com/android/server/vibrator/VibrationScaler.java
index 5d17884..d9ca710 100644
--- a/services/core/java/com/android/server/vibrator/VibrationScaler.java
+++ b/services/core/java/com/android/server/vibrator/VibrationScaler.java
@@ -26,10 +26,14 @@
 import android.os.vibrator.Flags;
 import android.os.vibrator.PrebakedSegment;
 import android.os.vibrator.VibrationEffectSegment;
+import android.util.IndentingPrintWriter;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Locale;
 
 /** Controls vibration scaling. */
 final class VibrationScaler {
@@ -37,13 +41,12 @@
 
     // Scale levels. Each level, except MUTE, is defined as the delta between the current setting
     // and the default intensity for that type of vibration (i.e. current - default).
-    private static final int SCALE_VERY_LOW =
-            ExternalVibrationScale.ScaleLevel.SCALE_VERY_LOW; // -2
-    private static final int SCALE_LOW = ExternalVibrationScale.ScaleLevel.SCALE_LOW; // -1
-    private static final int SCALE_NONE = ExternalVibrationScale.ScaleLevel.SCALE_NONE; // 0
-    private static final int SCALE_HIGH = ExternalVibrationScale.ScaleLevel.SCALE_HIGH; // 1
-    private static final int SCALE_VERY_HIGH =
-            ExternalVibrationScale.ScaleLevel.SCALE_VERY_HIGH; // 2
+    static final int SCALE_VERY_LOW = ExternalVibrationScale.ScaleLevel.SCALE_VERY_LOW; // -2
+    static final int SCALE_LOW = ExternalVibrationScale.ScaleLevel.SCALE_LOW; // -1
+    static final int SCALE_NONE = ExternalVibrationScale.ScaleLevel.SCALE_NONE; // 0
+    static final int SCALE_HIGH = ExternalVibrationScale.ScaleLevel.SCALE_HIGH; // 1
+    static final int SCALE_VERY_HIGH = ExternalVibrationScale.ScaleLevel.SCALE_VERY_HIGH; // 2
+    static final float ADAPTIVE_SCALE_NONE = 1f;
 
     // Scale factors for each level.
     private static final float SCALE_FACTOR_VERY_LOW = 0.6f;
@@ -52,6 +55,8 @@
     private static final float SCALE_FACTOR_HIGH = 1.2f;
     private static final float SCALE_FACTOR_VERY_HIGH = 1.4f;
 
+    private static final ScaleLevel SCALE_LEVEL_NONE = new ScaleLevel(SCALE_FACTOR_NONE);
+
     // A mapping from the intensity adjustment to the scaling to apply, where the intensity
     // adjustment is defined as the delta between the default intensity level and the user selected
     // intensity level. It's important that we apply the scaling on the delta between the two so
@@ -69,7 +74,7 @@
         mScaleLevels = new SparseArray<>();
         mScaleLevels.put(SCALE_VERY_LOW, new ScaleLevel(SCALE_FACTOR_VERY_LOW));
         mScaleLevels.put(SCALE_LOW, new ScaleLevel(SCALE_FACTOR_LOW));
-        mScaleLevels.put(SCALE_NONE, new ScaleLevel(SCALE_FACTOR_NONE));
+        mScaleLevels.put(SCALE_NONE, SCALE_LEVEL_NONE);
         mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_FACTOR_HIGH));
         mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_FACTOR_VERY_HIGH));
     }
@@ -87,25 +92,24 @@
      * @param usageHint one of VibrationAttributes.USAGE_*
      * @return one of ExternalVibrationScale.ScaleLevel.SCALE_*
      */
-    public int getExternalVibrationScaleLevel(int usageHint) {
+    public int getScaleLevel(int usageHint) {
         int defaultIntensity = mSettingsController.getDefaultIntensity(usageHint);
         int currentIntensity = mSettingsController.getCurrentIntensity(usageHint);
-
         if (currentIntensity == Vibrator.VIBRATION_INTENSITY_OFF) {
             // Bypassing user settings, or it has changed between checking and scaling. Use default.
             return SCALE_NONE;
         }
 
         int scaleLevel = currentIntensity - defaultIntensity;
-
         if (scaleLevel >= SCALE_VERY_LOW && scaleLevel <= SCALE_VERY_HIGH) {
             return scaleLevel;
-        } else {
-            // Something about our scaling has gone wrong, so just play with no scaling.
-            Slog.w(TAG, "Error in scaling calculations, ended up with invalid scale level "
-                    + scaleLevel + " for vibration with usage " + usageHint);
-            return SCALE_NONE;
         }
+
+        // Something about our scaling has gone wrong, so just play with no scaling.
+        Slog.wtf(TAG, "Error in scaling calculations, ended up with invalid scale level "
+                + scaleLevel + " for vibration with usage " + usageHint);
+
+        return SCALE_NONE;
     }
 
     /**
@@ -117,11 +121,9 @@
      * @return The adaptive haptics scale.
      */
     public float getAdaptiveHapticsScale(int usageHint) {
-        if (shouldApplyAdaptiveHapticsScale(usageHint)) {
-            return mAdaptiveHapticsScales.get(usageHint);
-        }
-
-        return 1f; // no scaling
+        return Flags.adaptiveHapticsEnabled()
+                ? mAdaptiveHapticsScales.get(usageHint, ADAPTIVE_SCALE_NONE)
+                : ADAPTIVE_SCALE_NONE;
     }
 
     /**
@@ -140,21 +142,16 @@
             return effect;
         }
 
-        int defaultIntensity = mSettingsController.getDefaultIntensity(usageHint);
-        int currentIntensity = mSettingsController.getCurrentIntensity(usageHint);
-
-        if (currentIntensity == Vibrator.VIBRATION_INTENSITY_OFF) {
-            // Bypassing user settings, or it has changed between checking and scaling. Use default.
-            currentIntensity = defaultIntensity;
-        }
-
-        int newEffectStrength = intensityToEffectStrength(currentIntensity);
-        ScaleLevel scaleLevel = mScaleLevels.get(currentIntensity - defaultIntensity);
+        int newEffectStrength = getEffectStrength(usageHint);
+        ScaleLevel scaleLevel = mScaleLevels.get(getScaleLevel(usageHint));
+        float adaptiveScale = getAdaptiveHapticsScale(usageHint);
 
         if (scaleLevel == null) {
             // Something about our scaling has gone wrong, so just play with no scaling.
-            Slog.e(TAG, "No configured scaling level!"
-                    + " (current=" + currentIntensity + ", default= " + defaultIntensity + ")");
+            Slog.e(TAG, "No configured scaling level found! (current="
+                    + mSettingsController.getCurrentIntensity(usageHint) + ", default= "
+                    + mSettingsController.getDefaultIntensity(usageHint) + ")");
+            scaleLevel = SCALE_LEVEL_NONE;
         }
 
         VibrationEffect.Composed composedEffect = (VibrationEffect.Composed) effect;
@@ -162,20 +159,11 @@
                 new ArrayList<>(composedEffect.getSegments());
         int segmentCount = segments.size();
         for (int i = 0; i < segmentCount; i++) {
-            VibrationEffectSegment segment = segments.get(i);
-            segment = segment.resolve(mDefaultVibrationAmplitude)
-                    .applyEffectStrength(newEffectStrength);
-            if (scaleLevel != null) {
-                segment = segment.scale(scaleLevel.factor);
-            }
-
-            // If adaptive haptics scaling is available for this usage, apply it to the segment.
-            if (shouldApplyAdaptiveHapticsScale(usageHint)) {
-                float adaptiveScale = mAdaptiveHapticsScales.get(usageHint);
-                segment = segment.scaleLinearly(adaptiveScale);
-            }
-
-            segments.set(i, segment);
+            segments.set(i,
+                    segments.get(i).resolve(mDefaultVibrationAmplitude)
+                            .applyEffectStrength(newEffectStrength)
+                            .scale(scaleLevel.factor)
+                            .scaleLinearly(adaptiveScale));
         }
         if (segments.equals(composedEffect.getSegments())) {
             // No segment was updated, return original effect.
@@ -197,15 +185,7 @@
      * updated effect strength
      */
     public PrebakedSegment scale(PrebakedSegment prebaked, int usageHint) {
-        int currentIntensity = mSettingsController.getCurrentIntensity(usageHint);
-
-        if (currentIntensity == Vibrator.VIBRATION_INTENSITY_OFF) {
-            // Bypassing user settings, or it has changed between checking and scaling. Use default.
-            currentIntensity = mSettingsController.getDefaultIntensity(usageHint);
-        }
-
-        int newEffectStrength = intensityToEffectStrength(currentIntensity);
-        return prebaked.applyEffectStrength(newEffectStrength);
+        return prebaked.applyEffectStrength(getEffectStrength(usageHint));
     }
 
     /**
@@ -213,8 +193,6 @@
      *
      * @param usageHint one of VibrationAttributes.USAGE_*.
      * @param scale The scaling factor that should be applied to vibrations of this usage.
-     *
-     * @hide
      */
     public void updateAdaptiveHapticsScale(@VibrationAttributes.Usage int usageHint, float scale) {
         mAdaptiveHapticsScales.put(usageHint, scale);
@@ -224,24 +202,68 @@
      * Removes the usage from the cached adaptive haptics scales list.
      *
      * @param usageHint one of VibrationAttributes.USAGE_*.
-     *
-     * @hide
      */
     public void removeAdaptiveHapticsScale(@VibrationAttributes.Usage int usageHint) {
         mAdaptiveHapticsScales.remove(usageHint);
     }
 
-    /**
-     * Removes all cached adaptive haptics scales.
-     *
-     * @hide
-     */
+    /** Removes all cached adaptive haptics scales. */
     public void clearAdaptiveHapticsScales() {
         mAdaptiveHapticsScales.clear();
     }
 
-    private boolean shouldApplyAdaptiveHapticsScale(int usageHint) {
-        return Flags.adaptiveHapticsEnabled() && mAdaptiveHapticsScales.contains(usageHint);
+    /** Write current settings into given {@link PrintWriter}. */
+    void dump(IndentingPrintWriter pw) {
+        pw.println("VibrationScaler:");
+        pw.increaseIndent();
+        pw.println("defaultVibrationAmplitude = " + mDefaultVibrationAmplitude);
+
+        pw.println("ScaleLevels:");
+        pw.increaseIndent();
+        for (int i = 0; i < mScaleLevels.size(); i++) {
+            int scaleLevelKey = mScaleLevels.keyAt(i);
+            ScaleLevel scaleLevel = mScaleLevels.valueAt(i);
+            pw.println(scaleLevelToString(scaleLevelKey) + " = " + scaleLevel);
+        }
+        pw.decreaseIndent();
+
+        pw.println("AdaptiveHapticsScales:");
+        pw.increaseIndent();
+        for (int i = 0; i < mAdaptiveHapticsScales.size(); i++) {
+            int usage = mAdaptiveHapticsScales.keyAt(i);
+            float scale = mAdaptiveHapticsScales.valueAt(i);
+            pw.println(VibrationAttributes.usageToString(usage)
+                    + " = " + String.format(Locale.ROOT, "%.2f", scale));
+        }
+        pw.decreaseIndent();
+
+        pw.decreaseIndent();
+    }
+
+    /** Write current settings into given {@link ProtoOutputStream}. */
+    void dump(ProtoOutputStream proto) {
+        proto.write(VibratorManagerServiceDumpProto.DEFAULT_VIBRATION_AMPLITUDE,
+                mDefaultVibrationAmplitude);
+    }
+
+    @Override
+    public String toString() {
+        return "VibrationScaler{"
+                + "mScaleLevels=" + mScaleLevels
+                + ", mDefaultVibrationAmplitude=" + mDefaultVibrationAmplitude
+                + ", mAdaptiveHapticsScales=" + mAdaptiveHapticsScales
+                + '}';
+    }
+
+    private int getEffectStrength(int usageHint) {
+        int currentIntensity = mSettingsController.getCurrentIntensity(usageHint);
+
+        if (currentIntensity == Vibrator.VIBRATION_INTENSITY_OFF) {
+            // Bypassing user settings, or it has changed between checking and scaling. Use default.
+            currentIntensity = mSettingsController.getDefaultIntensity(usageHint);
+        }
+
+        return intensityToEffectStrength(currentIntensity);
     }
 
     /** Mapping of Vibrator.VIBRATION_INTENSITY_* values to {@link EffectStrength}. */
@@ -259,6 +281,17 @@
         }
     }
 
+    static String scaleLevelToString(int scaleLevel) {
+        return switch (scaleLevel) {
+            case SCALE_VERY_LOW -> "VERY_LOW";
+            case SCALE_LOW -> "LOW";
+            case SCALE_NONE -> "NONE";
+            case SCALE_HIGH -> "HIGH";
+            case SCALE_VERY_HIGH -> "VERY_HIGH";
+            default -> String.valueOf(scaleLevel);
+        };
+    }
+
     /** Represents the scale that must be applied to a vibration effect intensity. */
     private static final class ScaleLevel {
         public final float factor;
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index 99ce3e2..5b77433 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -386,7 +386,6 @@
      * Returns the duration, in milliseconds, that the vibrator control service will wait for new
      * vibration params.
      * @return The request vibration params timeout in milliseconds.
-     * @hide
      */
     public int getRequestVibrationParamsTimeoutMs() {
         return mVibrationConfig.getRequestVibrationParamsTimeoutMs();
@@ -645,11 +644,16 @@
                         .append("), ");
             }
             vibrationIntensitiesString.append('}');
+            String keyboardVibrationOnString = mKeyboardVibrationOn
+                    + " (default: " + mVibrationConfig.isDefaultKeyboardVibrationEnabled() + ")";
             return "VibrationSettings{"
                     + "mVibratorConfig=" + mVibrationConfig
+                    + ", mVibrateOn=" + mVibrateOn
+                    + ", mKeyboardVibrationOn=" + keyboardVibrationOnString
                     + ", mVibrateInputDevices=" + mVibrateInputDevices
                     + ", mBatterySaverMode=" + mBatterySaverMode
-                    + ", mVibrateOn=" + mVibrateOn
+                    + ", mRingerMode=" + ringerModeToString(mRingerMode)
+                    + ", mOnWirelessCharger=" + mOnWirelessCharger
                     + ", mVibrationIntensities=" + vibrationIntensitiesString
                     + ", mProcStatesCache=" + mUidObserver.mProcStatesCache
                     + '}';
@@ -658,32 +662,40 @@
 
     /** Write current settings into given {@link PrintWriter}. */
     void dump(IndentingPrintWriter pw) {
-        pw.println("VibrationSettings:");
-        pw.increaseIndent();
-        pw.println("vibrateOn = " + mVibrateOn);
-        pw.println("vibrateInputDevices = " + mVibrateInputDevices);
-        pw.println("batterySaverMode = " + mBatterySaverMode);
-        pw.println("VibrationIntensities:");
+        synchronized (mLock) {
+            pw.println("VibrationSettings:");
+            pw.increaseIndent();
+            pw.println("vibrateOn = " + mVibrateOn);
+            pw.println("keyboardVibrationOn = " + mKeyboardVibrationOn
+                    + ", default: " + mVibrationConfig.isDefaultKeyboardVibrationEnabled());
+            pw.println("vibrateInputDevices = " + mVibrateInputDevices);
+            pw.println("batterySaverMode = " + mBatterySaverMode);
+            pw.println("ringerMode = " + ringerModeToString(mRingerMode));
+            pw.println("onWirelessCharger = " + mOnWirelessCharger);
+            pw.println("processStateCache size = " + mUidObserver.mProcStatesCache.size());
 
-        pw.increaseIndent();
-        for (int i = 0; i < mCurrentVibrationIntensities.size(); i++) {
-            int usage = mCurrentVibrationIntensities.keyAt(i);
-            int intensity = mCurrentVibrationIntensities.valueAt(i);
-            pw.println(VibrationAttributes.usageToString(usage) + " = "
-                    + intensityToString(intensity)
-                    + ", default: " + intensityToString(getDefaultIntensity(usage)));
+            pw.println("VibrationIntensities:");
+            pw.increaseIndent();
+            for (int i = 0; i < mCurrentVibrationIntensities.size(); i++) {
+                int usage = mCurrentVibrationIntensities.keyAt(i);
+                int intensity = mCurrentVibrationIntensities.valueAt(i);
+                pw.println(VibrationAttributes.usageToString(usage) + " = "
+                        + intensityToString(intensity)
+                        + ", default: " + intensityToString(getDefaultIntensity(usage)));
+            }
+            pw.decreaseIndent();
+
+            mVibrationConfig.dumpWithoutDefaultSettings(pw);
+            pw.decreaseIndent();
         }
-        pw.decreaseIndent();
-
-        mVibrationConfig.dumpWithoutDefaultSettings(pw);
-        pw.println("processStateCache = " + mUidObserver.mProcStatesCache);
-        pw.decreaseIndent();
     }
 
     /** Write current settings into given {@link ProtoOutputStream}. */
     void dump(ProtoOutputStream proto) {
         synchronized (mLock) {
             proto.write(VibratorManagerServiceDumpProto.VIBRATE_ON, mVibrateOn);
+            proto.write(VibratorManagerServiceDumpProto.KEYBOARD_VIBRATION_ON,
+                    mKeyboardVibrationOn);
             proto.write(VibratorManagerServiceDumpProto.LOW_POWER_MODE, mBatterySaverMode);
             proto.write(VibratorManagerServiceDumpProto.ALARM_INTENSITY,
                     getCurrentIntensity(USAGE_ALARM));
@@ -723,18 +735,22 @@
     }
 
     private static String intensityToString(int intensity) {
-        switch (intensity) {
-            case Vibrator.VIBRATION_INTENSITY_OFF:
-                return "OFF";
-            case Vibrator.VIBRATION_INTENSITY_LOW:
-                return "LOW";
-            case Vibrator.VIBRATION_INTENSITY_MEDIUM:
-                return "MEDIUM";
-            case Vibrator.VIBRATION_INTENSITY_HIGH:
-                return "HIGH";
-            default:
-                return "UNKNOWN INTENSITY " + intensity;
-        }
+        return switch (intensity) {
+            case Vibrator.VIBRATION_INTENSITY_OFF -> "OFF";
+            case Vibrator.VIBRATION_INTENSITY_LOW -> "LOW";
+            case Vibrator.VIBRATION_INTENSITY_MEDIUM -> "MEDIUM";
+            case Vibrator.VIBRATION_INTENSITY_HIGH -> "HIGH";
+            default -> "UNKNOWN INTENSITY " + intensity;
+        };
+    }
+
+    private static String ringerModeToString(int ringerMode) {
+        return switch (ringerMode) {
+            case AudioManager.RINGER_MODE_SILENT -> "silent";
+            case AudioManager.RINGER_MODE_VIBRATE -> "vibrate";
+            case AudioManager.RINGER_MODE_NORMAL -> "normal";
+            default -> String.valueOf(ringerMode);
+        };
     }
 
     @VibrationIntensity
diff --git a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
index f6af9ad..f510b4e 100644
--- a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
+++ b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
@@ -161,7 +161,7 @@
                 waitForVibrationParamsIfRequired();
             }
             // Scale resolves the default amplitudes from the effect before scaling them.
-            mVibration.scaleEffects(mVibrationScaler::scale);
+            mVibration.scaleEffects(mVibrationScaler);
         } else {
             mVibration.resolveEffects(mVibrationScaler.getDefaultVibrationAmplitude());
         }
diff --git a/services/core/java/com/android/server/vibrator/VibratorControlService.java b/services/core/java/com/android/server/vibrator/VibratorControlService.java
index 17a9e33..ec3d99b 100644
--- a/services/core/java/com/android/server/vibrator/VibratorControlService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorControlService.java
@@ -30,6 +30,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
+import android.content.Context;
 import android.frameworks.vibrator.IVibratorControlService;
 import android.frameworks.vibrator.IVibratorController;
 import android.frameworks.vibrator.ScaleParam;
@@ -37,27 +38,38 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
+import android.util.IndentingPrintWriter;
+import android.util.IntArray;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
 import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
 
 /**
  * Implementation of {@link IVibratorControlService} which allows the registration of
  * {@link IVibratorController} to set and receive vibration params.
- *
- * @hide
  */
-public final class VibratorControlService extends IVibratorControlService.Stub {
+final class VibratorControlService extends IVibratorControlService.Stub {
     private static final String TAG = "VibratorControlService";
     private static final int UNRECOGNIZED_VIBRATION_TYPE = -1;
     private static final int NO_SCALE = -1;
 
+    private static final SimpleDateFormat DEBUG_DATE_TIME_FORMAT =
+            new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
+
+    private final VibrationParamsRecords mVibrationParamsRecords;
     private final VibratorControllerHolder mVibratorControllerHolder;
     private final VibrationScaler mVibrationScaler;
     private final Object mLock;
@@ -68,25 +80,32 @@
     @GuardedBy("mLock")
     private IBinder mRequestVibrationParamsToken;
 
-    public VibratorControlService(VibratorControllerHolder vibratorControllerHolder,
-            VibrationScaler vibrationScaler, VibrationSettings vibrationSettings, Object lock) {
+    VibratorControlService(Context context,
+            VibratorControllerHolder vibratorControllerHolder, VibrationScaler vibrationScaler,
+            VibrationSettings vibrationSettings, Object lock) {
         mVibratorControllerHolder = vibratorControllerHolder;
         mVibrationScaler = vibrationScaler;
         mLock = lock;
         mRequestVibrationParamsForUsages = vibrationSettings.getRequestVibrationParamsForUsages();
+
+        int dumpSizeLimit = context.getResources().getInteger(
+                com.android.internal.R.integer.config_previousVibrationsDumpSizeLimit);
+        int dumpAggregationTimeLimit = context.getResources().getInteger(
+                com.android.internal.R.integer
+                        .config_previousVibrationsDumpAggregationTimeMillisLimit);
+        mVibrationParamsRecords =
+                new VibrationParamsRecords(dumpSizeLimit, dumpAggregationTimeLimit);
     }
 
     @Override
-    public void registerVibratorController(IVibratorController controller)
-            throws RemoteException {
+    public void registerVibratorController(IVibratorController controller) {
         synchronized (mLock) {
             mVibratorControllerHolder.setVibratorController(controller);
         }
     }
 
     @Override
-    public void unregisterVibratorController(@NonNull IVibratorController controller)
-            throws RemoteException {
+    public void unregisterVibratorController(@NonNull IVibratorController controller) {
         Objects.requireNonNull(controller);
 
         synchronized (mLock) {
@@ -110,7 +129,7 @@
 
     @Override
     public void setVibrationParams(@SuppressLint("ArrayReturn") VibrationParam[] params,
-            @NonNull IVibratorController token) throws RemoteException {
+            @NonNull IVibratorController token) {
         Objects.requireNonNull(token);
 
         synchronized (mLock) {
@@ -128,12 +147,12 @@
             }
 
             updateAdaptiveHapticsScales(params);
+            recordUpdateVibrationParams(params, /* fromRequest= */ false);
         }
     }
 
     @Override
-    public void clearVibrationParams(int types, @NonNull IVibratorController token)
-            throws RemoteException {
+    public void clearVibrationParams(int types, @NonNull IVibratorController token) {
         Objects.requireNonNull(token);
 
         synchronized (mLock) {
@@ -151,13 +170,13 @@
             }
 
             updateAdaptiveHapticsScales(types, NO_SCALE);
+            recordClearVibrationParams(types);
         }
     }
 
     @Override
     public void onRequestVibrationParamsComplete(
-            @NonNull IBinder requestToken, @SuppressLint("ArrayReturn") VibrationParam[] result)
-            throws RemoteException {
+            @NonNull IBinder requestToken, @SuppressLint("ArrayReturn") VibrationParam[] result) {
         Objects.requireNonNull(requestToken);
 
         synchronized (mLock) {
@@ -177,16 +196,17 @@
 
             updateAdaptiveHapticsScales(result);
             endOngoingRequestVibrationParamsLocked(/* wasCancelled= */ false);
+            recordUpdateVibrationParams(result, /* fromRequest= */ true);
         }
     }
 
     @Override
-    public int getInterfaceVersion() throws RemoteException {
+    public int getInterfaceVersion() {
         return this.VERSION;
     }
 
     @Override
-    public String getInterfaceHash() throws RemoteException {
+    public String getInterfaceHash() {
         return this.HASH;
     }
 
@@ -266,6 +286,42 @@
         }
     }
 
+    /** Write current settings into given {@link PrintWriter}. */
+    void dump(IndentingPrintWriter pw) {
+        boolean isVibratorControllerRegistered;
+        boolean hasPendingVibrationParamsRequest;
+        synchronized (mLock) {
+            isVibratorControllerRegistered =
+                    mVibratorControllerHolder.getVibratorController() != null;
+            hasPendingVibrationParamsRequest = mRequestVibrationParamsFuture != null;
+        }
+
+        pw.println("VibratorControlService:");
+        pw.increaseIndent();
+        pw.println("isVibratorControllerRegistered = " + isVibratorControllerRegistered);
+        pw.println("hasPendingVibrationParamsRequest = " + hasPendingVibrationParamsRequest);
+
+        pw.println();
+        pw.println("Vibration parameters update history:");
+        pw.increaseIndent();
+        mVibrationParamsRecords.dump(pw);
+        pw.decreaseIndent();
+
+        pw.decreaseIndent();
+    }
+
+    /** Write current settings into given {@link ProtoOutputStream}. */
+    void dump(ProtoOutputStream proto) {
+        boolean isVibratorControllerRegistered;
+        synchronized (mLock) {
+            isVibratorControllerRegistered =
+                    mVibratorControllerHolder.getVibratorController() != null;
+        }
+        proto.write(VibratorManagerServiceDumpProto.IS_VIBRATOR_CONTROLLER_REGISTERED,
+                isVibratorControllerRegistered);
+        mVibrationParamsRecords.dump(proto);
+    }
+
     /**
      * Completes or cancels the vibration params request future and resets the future and token
      * to null.
@@ -312,6 +368,33 @@
         }
     }
 
+    private static int[] mapFromAdaptiveVibrationTypeToVibrationUsages(int types) {
+        IntArray usages = new IntArray(15);
+        if ((ScaleParam.TYPE_ALARM & types) != 0) {
+            usages.add(USAGE_ALARM);
+        }
+
+        if ((ScaleParam.TYPE_NOTIFICATION & types) != 0) {
+            usages.add(USAGE_NOTIFICATION);
+            usages.add(USAGE_COMMUNICATION_REQUEST);
+        }
+
+        if ((ScaleParam.TYPE_RINGTONE & types) != 0) {
+            usages.add(USAGE_RINGTONE);
+        }
+
+        if ((ScaleParam.TYPE_MEDIA & types) != 0) {
+            usages.add(USAGE_MEDIA);
+            usages.add(USAGE_UNKNOWN);
+        }
+
+        if ((ScaleParam.TYPE_INTERACTIVE & types) != 0) {
+            usages.add(USAGE_TOUCH);
+            usages.add(USAGE_HARDWARE_FEEDBACK);
+        }
+        return usages.toArray();
+    }
+
     /**
      * Updates the adaptive haptics scales cached in {@link VibrationScaler} with the
      * provided params.
@@ -319,7 +402,14 @@
      * @param params the new vibration params.
      */
     private void updateAdaptiveHapticsScales(@Nullable VibrationParam[] params) {
+        if (params == null) {
+            return;
+        }
         for (VibrationParam param : params) {
+            if (param.getTag() != VibrationParam.scale) {
+                Slog.e(TAG, "Unsupported vibration param: " + param);
+                continue;
+            }
             ScaleParam scaleParam = param.getScale();
             updateAdaptiveHapticsScales(scaleParam.typesMask, scaleParam.scale);
         }
@@ -333,27 +423,8 @@
      * @param scale The scaling factor that should be applied to the vibrations.
      */
     private void updateAdaptiveHapticsScales(int types, float scale) {
-        if ((ScaleParam.TYPE_ALARM & types) != 0) {
-            updateOrRemoveAdaptiveHapticsScale(USAGE_ALARM, scale);
-        }
-
-        if ((ScaleParam.TYPE_NOTIFICATION & types) != 0) {
-            updateOrRemoveAdaptiveHapticsScale(USAGE_NOTIFICATION, scale);
-            updateOrRemoveAdaptiveHapticsScale(USAGE_COMMUNICATION_REQUEST, scale);
-        }
-
-        if ((ScaleParam.TYPE_RINGTONE & types) != 0) {
-            updateOrRemoveAdaptiveHapticsScale(USAGE_RINGTONE, scale);
-        }
-
-        if ((ScaleParam.TYPE_MEDIA & types) != 0) {
-            updateOrRemoveAdaptiveHapticsScale(USAGE_MEDIA, scale);
-            updateOrRemoveAdaptiveHapticsScale(USAGE_UNKNOWN, scale);
-        }
-
-        if ((ScaleParam.TYPE_INTERACTIVE & types) != 0) {
-            updateOrRemoveAdaptiveHapticsScale(USAGE_TOUCH, scale);
-            updateOrRemoveAdaptiveHapticsScale(USAGE_HARDWARE_FEEDBACK, scale);
+        for (int usage : mapFromAdaptiveVibrationTypeToVibrationUsages(types)) {
+            updateOrRemoveAdaptiveHapticsScale(usage, scale);
         }
     }
 
@@ -375,4 +446,136 @@
 
         mVibrationScaler.updateAdaptiveHapticsScale(usageHint, scale);
     }
+
+    private void recordUpdateVibrationParams(@Nullable VibrationParam[] params,
+            boolean fromRequest) {
+        if (params == null) {
+            return;
+        }
+        VibrationParamsRecords.Operation operation =
+                fromRequest ? VibrationParamsRecords.Operation.PULL
+                        : VibrationParamsRecords.Operation.PUSH;
+        long createTime = SystemClock.uptimeMillis();
+        for (VibrationParam param : params) {
+            if (param.getTag() != VibrationParam.scale) {
+                Slog.w(TAG, "Unsupported vibration param ignored from dumpsys records: " + param);
+                continue;
+            }
+            ScaleParam scaleParam = param.getScale();
+            mVibrationParamsRecords.add(new VibrationScaleParamRecord(operation, createTime,
+                    scaleParam.typesMask, scaleParam.scale));
+        }
+    }
+
+    private void recordClearVibrationParams(int typesMask) {
+        long createTime = SystemClock.uptimeMillis();
+        mVibrationParamsRecords.add(new VibrationScaleParamRecord(
+                VibrationParamsRecords.Operation.CLEAR, createTime, typesMask, NO_SCALE));
+    }
+
+    /**
+     * Keep records of {@link VibrationParam} values received by this service from a registered
+     * {@link VibratorController} and provide debug information for this service.
+     */
+    private static final class VibrationParamsRecords
+            extends GroupedAggregatedLogRecords<VibrationScaleParamRecord> {
+
+        /** The type of operations on vibration parameters that the service is recording. */
+        enum Operation {
+            PULL, PUSH, CLEAR
+        };
+
+        VibrationParamsRecords(int sizeLimit, int aggregationTimeLimit) {
+            super(sizeLimit, aggregationTimeLimit);
+        }
+
+        @Override
+        synchronized void dumpGroupHeader(IndentingPrintWriter pw, int paramType) {
+            if (paramType == VibrationParam.scale) {
+                pw.println("SCALE:");
+            } else {
+                pw.println("UNKNOWN:");
+            }
+        }
+
+        @Override
+        synchronized long findGroupKeyProtoFieldId(int usage) {
+            return VibratorManagerServiceDumpProto.PREVIOUS_VIBRATION_PARAMS;
+        }
+    }
+
+    /**
+     * Record for a single {@link Vibration.DebugInfo}, that can be grouped by usage and aggregated
+     * by UID, {@link VibrationAttributes} and {@link VibrationEffect}.
+     */
+    private static final class VibrationScaleParamRecord
+            implements GroupedAggregatedLogRecords.SingleLogRecord {
+
+        private final VibrationParamsRecords.Operation mOperation;
+        private final long mCreateTime;
+        private final int mTypesMask;
+        private final float mScale;
+
+        VibrationScaleParamRecord(VibrationParamsRecords.Operation operation, long createTime,
+                int typesMask, float scale) {
+            mOperation = operation;
+            mCreateTime = createTime;
+            mTypesMask = typesMask;
+            mScale = scale;
+        }
+
+        @Override
+        public int getGroupKey() {
+            return VibrationParam.scale;
+        }
+
+        @Override
+        public long getCreateUptimeMs() {
+            return mCreateTime;
+        }
+
+        @Override
+        public boolean mayAggregate(GroupedAggregatedLogRecords.SingleLogRecord record) {
+            if (!(record instanceof VibrationScaleParamRecord param)) {
+                return false;
+            }
+            return mTypesMask == param.mTypesMask && mOperation == param.mOperation;
+        }
+
+        @Override
+        public void dump(IndentingPrintWriter pw) {
+            String line = String.format(Locale.ROOT,
+                    "%s | %6s | scale: %5s | typesMask: %6s | usages: %s",
+                    DEBUG_DATE_TIME_FORMAT.format(new Date(mCreateTime)),
+                    mOperation.name().toLowerCase(Locale.ROOT),
+                    (mScale == NO_SCALE) ? "" : String.format(Locale.ROOT, "%.2f", mScale),
+                    Long.toBinaryString(mTypesMask), createVibrationUsagesString());
+            pw.println(line);
+        }
+
+        @Override
+        public void dump(ProtoOutputStream proto, long fieldId) {
+            final long token = proto.start(fieldId);
+            proto.write(VibrationParamProto.CREATE_TIME, mCreateTime);
+            proto.write(VibrationParamProto.IS_FROM_REQUEST,
+                    mOperation == VibrationParamsRecords.Operation.PULL);
+
+            final long scaleToken = proto.start(VibrationParamProto.SCALE);
+            proto.write(VibrationScaleParamProto.TYPES_MASK, mTypesMask);
+            proto.write(VibrationScaleParamProto.SCALE, mScale);
+            proto.end(scaleToken);
+
+            proto.end(token);
+        }
+
+        private String createVibrationUsagesString() {
+            StringBuilder sb = new StringBuilder();
+            int[] usages = mapFromAdaptiveVibrationTypeToVibrationUsages(mTypesMask);
+            for (int i = 0; i < usages.length; i++) {
+                if (i > 0) sb.append(", ");
+                sb.append(VibrationAttributes.usageToString(usages[i]));
+            }
+            return sb.toString();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java
index f5d4d1e..6710d02 100644
--- a/services/core/java/com/android/server/vibrator/VibratorController.java
+++ b/services/core/java/com/android/server/vibrator/VibratorController.java
@@ -17,7 +17,6 @@
 package com.android.server.vibrator;
 
 import android.annotation.Nullable;
-import android.annotation.Nullable;
 import android.hardware.vibrator.IVibrator;
 import android.os.Binder;
 import android.os.IVibratorStateListener;
@@ -354,13 +353,13 @@
     }
 
     void dump(IndentingPrintWriter pw) {
-        pw.println("VibratorController:");
+        pw.println("Vibrator (id=" + mVibratorInfo.getId() + "):");
         pw.increaseIndent();
         pw.println("isVibrating = " + mIsVibrating);
         pw.println("isUnderExternalControl = " + mIsUnderExternalControl);
         pw.println("currentAmplitude = " + mCurrentAmplitude);
         pw.println("vibratorInfoLoadSuccessful = " + mVibratorInfoLoadSuccessful);
-        pw.println("vibratorStateListenerCount = "
+        pw.println("vibratorStateListener size = "
                 + mVibratorStateListeners.getRegisteredCallbackCount());
         mVibratorInfo.dump(pw);
         pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/vibrator/VibratorControllerHolder.java b/services/core/java/com/android/server/vibrator/VibratorControllerHolder.java
index 79a99b3..b49fb85 100644
--- a/services/core/java/com/android/server/vibrator/VibratorControllerHolder.java
+++ b/services/core/java/com/android/server/vibrator/VibratorControllerHolder.java
@@ -24,8 +24,6 @@
 
 /**
  * Holder class for {@link IVibratorController}.
- *
- * @hide
  */
 public final class VibratorControllerHolder implements IBinder.DeathRecipient {
     private static final String TAG = "VibratorControllerHolder";
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 78e0ebb..c1bf039 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -16,7 +16,6 @@
 
 package com.android.server.vibrator;
 
-import static android.os.ExternalVibrationScale.ScaleLevel.SCALE_MUTE;
 import static android.os.VibrationEffect.VibrationParameter.targetAmplitude;
 import static android.os.VibrationEffect.VibrationParameter.targetFrequency;
 
@@ -84,7 +83,6 @@
 import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
@@ -217,7 +215,7 @@
 
         mVibrationSettings = new VibrationSettings(mContext, mHandler);
         mVibrationScaler = new VibrationScaler(mContext, mVibrationSettings);
-        mVibratorControlService = new VibratorControlService(
+        mVibratorControlService = new VibratorControlService(mContext,
                 injector.createVibratorControllerHolder(), mVibrationScaler, mVibrationSettings,
                 mLock);
         mInputDeviceDelegate = new InputDeviceDelegate(mContext, mHandler);
@@ -416,14 +414,14 @@
     }
 
     @Override // Binder call
-    public void performHapticFeedback(
-            int uid, int deviceId, String opPkg, int constant, boolean always, String reason) {
+    public void performHapticFeedback(int uid, int deviceId, String opPkg, int constant,
+            boolean always, String reason, boolean fromIme) {
         // Note that the `performHapticFeedback` method does not take a token argument from the
         // caller, and instead, uses this service as the token. This is to mitigate performance
         // impact that would otherwise be caused due to marshal latency. Haptic feedback effects are
         // short-lived, so we don't need to cancel when the process dies.
         performHapticFeedbackInternal(
-                uid, deviceId, opPkg, constant, always, reason, /* token= */ this);
+                uid, deviceId, opPkg, constant, always, reason, /* token= */ this, fromIme);
     }
 
     /**
@@ -435,7 +433,7 @@
     @Nullable
     HalVibration performHapticFeedbackInternal(
             int uid, int deviceId, String opPkg, int constant, boolean always, String reason,
-            IBinder token) {
+            IBinder token, boolean fromIme) {
         HapticFeedbackVibrationProvider hapticVibrationProvider = getHapticVibrationProvider();
         if (hapticVibrationProvider == null) {
             Slog.w(TAG, "performHapticFeedback; haptic vibration provider not ready.");
@@ -449,7 +447,7 @@
         CombinedVibration combinedVibration = CombinedVibration.createParallel(effect);
         VibrationAttributes attrs =
                 hapticVibrationProvider.getVibrationAttributesForHapticFeedback(
-                        constant, /* bypassVibrationIntensitySetting= */ always);
+                        constant, /* bypassVibrationIntensitySetting= */ always, fromIme);
         VibratorFrameworkStatsLogger.logPerformHapticsFeedbackIfKeyboard(uid, constant);
         return vibrateWithoutPermissionCheck(uid, deviceId, opPkg, combinedVibration, attrs,
                 "performHapticFeedback: " + reason, token);
@@ -639,13 +637,16 @@
         }
         IndentingPrintWriter pw = new IndentingPrintWriter(w, /* singleIndent= */ "  ");
         synchronized (mLock) {
-            pw.println("Vibrator Manager Service:");
+            pw.println("VibratorManagerService:");
             pw.increaseIndent();
 
             mVibrationSettings.dump(pw);
             pw.println();
 
-            pw.println("VibratorControllers:");
+            mVibrationScaler.dump(pw);
+            pw.println();
+
+            pw.println("Vibrators:");
             pw.increaseIndent();
             for (int i = 0; i < mVibrators.size(); i++) {
                 mVibrators.valueAt(i).dump(pw);
@@ -686,6 +687,10 @@
         pw.println();
         pw.println();
         mVibratorManagerRecords.dump(pw);
+
+        pw.println();
+        pw.println();
+        mVibratorControlService.dump(pw);
     }
 
     private void dumpProto(FileDescriptor fd) {
@@ -695,6 +700,7 @@
         }
         synchronized (mLock) {
             mVibrationSettings.dump(proto);
+            mVibrationScaler.dump(proto);
             if (mCurrentVibration != null) {
                 mCurrentVibration.getVibration().getDebugInfo().dump(proto,
                         VibratorManagerServiceDumpProto.CURRENT_VIBRATION);
@@ -716,6 +722,7 @@
                     isUnderExternalControl);
         }
         mVibratorManagerRecords.dump(proto);
+        mVibratorControlService.dump(proto);
         proto.flush();
     }
 
@@ -887,7 +894,7 @@
         if (!vib.callerInfo.attrs.isFlagSet(
                 VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE)) {
             // Scale resolves the default amplitudes from the effect before scaling them.
-            vib.scaleEffects(mVibrationScaler::scale);
+            vib.scaleEffects(mVibrationScaler);
         } else {
             vib.resolveEffects(mVibrationScaler.getDefaultVibrationAmplitude());
         }
@@ -1663,7 +1670,8 @@
 
         public Vibration.DebugInfo getDebugInfo() {
             return new Vibration.DebugInfo(mStatus, stats, /* playedEffect= */ null,
-                    /* originalEffect= */ null, scale.scaleLevel, callerInfo);
+                    /* originalEffect= */ null, scale.scaleLevel, scale.adaptiveHapticsScale,
+                    callerInfo);
         }
 
         public VibrationStats.StatsInfo getStatsInfo(long completionUptimeMillis) {
@@ -1739,8 +1747,9 @@
                 int aggregationTimeLimit) {
             mAggregatedVibrationHistory =
                     new VibrationRecords(aggregationSizeLimit, aggregationTimeLimit);
-            mRecentVibrations = new VibrationRecords(
-                    recentVibrationSizeLimit, /* aggregationTimeLimit= */ 0);
+            // Recent vibrations are not aggregated, to help debugging issues that just happened.
+            mRecentVibrations =
+                    new VibrationRecords(recentVibrationSizeLimit, /* aggregationTimeLimit= */ 0);
         }
 
         synchronized void record(HalVibration vib) {
@@ -1752,9 +1761,11 @@
         }
 
         private synchronized void record(Vibration.DebugInfo info) {
-            AggregatedVibrationRecord removedRecord = mRecentVibrations.record(info);
-            if (removedRecord != null) {
-                mAggregatedVibrationHistory.record(removedRecord.mLatestVibration);
+            GroupedAggregatedLogRecords.AggregatedLogRecord<VibrationRecord> droppedRecord =
+                    mRecentVibrations.add(new VibrationRecord(info));
+            if (droppedRecord != null) {
+                // Move dropped record from recent list to aggregated history list.
+                mAggregatedVibrationHistory.add(droppedRecord.getLatest());
             }
         }
 
@@ -1763,9 +1774,9 @@
             pw.increaseIndent();
             mRecentVibrations.dump(pw);
             pw.decreaseIndent();
-            pw.println();
-            pw.println();
 
+            pw.println();
+            pw.println();
             pw.println("Aggregated vibration history:");
             pw.increaseIndent();
             mAggregatedVibrationHistory.dump(pw);
@@ -1778,127 +1789,75 @@
     }
 
     /** Keep records of vibrations played and provide debug information for this service. */
-    private static final class VibrationRecords {
-        private final SparseArray<LinkedList<AggregatedVibrationRecord>> mVibrations =
-                new SparseArray<>();
-        private final int mSizeLimit;
-        private final int mAggregationTimeLimit;
+    private static final class VibrationRecords
+            extends GroupedAggregatedLogRecords<VibrationRecord> {
 
         VibrationRecords(int sizeLimit, int aggregationTimeLimit) {
-            mSizeLimit = sizeLimit;
-            mAggregationTimeLimit = aggregationTimeLimit;
+            super(sizeLimit, aggregationTimeLimit);
         }
 
-        synchronized AggregatedVibrationRecord record(Vibration.DebugInfo info) {
-            int usage = info.mCallerInfo.attrs.getUsage();
-            if (!mVibrations.contains(usage)) {
-                mVibrations.put(usage, new LinkedList<>());
-            }
-            LinkedList<AggregatedVibrationRecord> records = mVibrations.get(usage);
-            if (mAggregationTimeLimit > 0 && !records.isEmpty()) {
-                AggregatedVibrationRecord lastRecord = records.getLast();
-                if (lastRecord.mayAggregate(info, mAggregationTimeLimit)) {
-                    lastRecord.record(info);
-                    return null;
-                }
-            }
-            AggregatedVibrationRecord removedRecord = null;
-            if (records.size() > mSizeLimit) {
-                removedRecord = records.removeFirst();
-            }
-            records.addLast(new AggregatedVibrationRecord(info));
-            return removedRecord;
+        @Override
+        void dumpGroupHeader(IndentingPrintWriter pw, int usage) {
+            pw.println(VibrationAttributes.usageToString(usage) + ":");
         }
 
-        synchronized void dump(IndentingPrintWriter pw) {
-            for (int i = 0; i < mVibrations.size(); i++) {
-                pw.println(VibrationAttributes.usageToString(mVibrations.keyAt(i)) + ":");
-                pw.increaseIndent();
-                for (AggregatedVibrationRecord info : mVibrations.valueAt(i)) {
-                    info.dump(pw);
-                }
-                pw.decreaseIndent();
-                pw.println();
-            }
-        }
-
-        synchronized void dump(ProtoOutputStream proto) {
-            for (int i = 0; i < mVibrations.size(); i++) {
-                long fieldId;
-                switch (mVibrations.keyAt(i)) {
-                    case VibrationAttributes.USAGE_RINGTONE:
-                        fieldId = VibratorManagerServiceDumpProto.PREVIOUS_RING_VIBRATIONS;
-                        break;
-                    case VibrationAttributes.USAGE_NOTIFICATION:
-                        fieldId = VibratorManagerServiceDumpProto.PREVIOUS_NOTIFICATION_VIBRATIONS;
-                        break;
-                    case VibrationAttributes.USAGE_ALARM:
-                        fieldId = VibratorManagerServiceDumpProto.PREVIOUS_ALARM_VIBRATIONS;
-                        break;
-                    default:
-                        fieldId = VibratorManagerServiceDumpProto.PREVIOUS_VIBRATIONS;
-                }
-                for (AggregatedVibrationRecord info : mVibrations.valueAt(i)) {
-                    if (info.mLatestVibration.mPlayedEffect == null) {
-                        // External vibrations are reported separately in the dump proto
-                        info.dump(proto,
-                                VibratorManagerServiceDumpProto.PREVIOUS_EXTERNAL_VIBRATIONS);
-                    } else {
-                        info.dump(proto, fieldId);
-                    }
-                }
-            }
-        }
-
-        synchronized void dumpOnSingleField(ProtoOutputStream proto, long fieldId) {
-            for (int i = 0; i < mVibrations.size(); i++) {
-                for (AggregatedVibrationRecord info : mVibrations.valueAt(i)) {
-                    info.dump(proto, fieldId);
-                }
-            }
+        @Override
+        long findGroupKeyProtoFieldId(int usage) {
+            return switch (usage) {
+                case VibrationAttributes.USAGE_RINGTONE ->
+                    VibratorManagerServiceDumpProto.PREVIOUS_RING_VIBRATIONS;
+                case VibrationAttributes.USAGE_NOTIFICATION ->
+                    VibratorManagerServiceDumpProto.PREVIOUS_NOTIFICATION_VIBRATIONS;
+                case VibrationAttributes.USAGE_ALARM ->
+                    VibratorManagerServiceDumpProto.PREVIOUS_ALARM_VIBRATIONS;
+                default ->
+                    VibratorManagerServiceDumpProto.PREVIOUS_VIBRATIONS;
+            };
         }
     }
 
     /**
-     * Record that keeps the last {@link Vibration.DebugInfo} played, aggregating close vibrations
-     * from the same uid that have the same {@link VibrationAttributes} and {@link VibrationEffect}.
+     * Record for a single {@link Vibration.DebugInfo}, that can be grouped by usage and aggregated
+     * by UID, {@link VibrationAttributes} and {@link VibrationEffect}.
      */
-    private static final class AggregatedVibrationRecord {
-        private final Vibration.DebugInfo mFirstVibration;
-        private Vibration.DebugInfo mLatestVibration;
-        private int mVibrationCount;
+    private static final class VibrationRecord
+            implements GroupedAggregatedLogRecords.SingleLogRecord {
+        private final Vibration.DebugInfo mInfo;
 
-        AggregatedVibrationRecord(Vibration.DebugInfo info) {
-            mLatestVibration = mFirstVibration = info;
-            mVibrationCount = 1;
+        VibrationRecord(Vibration.DebugInfo info) {
+            mInfo = info;
         }
 
-        synchronized boolean mayAggregate(Vibration.DebugInfo info, long timeLimit) {
-            return Objects.equals(mLatestVibration.mCallerInfo.uid, info.mCallerInfo.uid)
-                    && Objects.equals(mLatestVibration.mCallerInfo.attrs, info.mCallerInfo.attrs)
-                    && Objects.equals(mLatestVibration.mPlayedEffect, info.mPlayedEffect)
-                    && Math.abs(mLatestVibration.mCreateTime - info.mCreateTime) < timeLimit;
+        @Override
+        public int getGroupKey() {
+            return mInfo.mCallerInfo.attrs.getUsage();
         }
 
-        synchronized void record(Vibration.DebugInfo vib) {
-            mLatestVibration = vib;
-            mVibrationCount++;
+        @Override
+        public long getCreateUptimeMs() {
+            return mInfo.mCreateTime;
         }
 
-        synchronized void dump(IndentingPrintWriter pw) {
-            mFirstVibration.dumpCompact(pw);
-            if (mVibrationCount == 1) {
-                return;
+        @Override
+        public boolean mayAggregate(GroupedAggregatedLogRecords.SingleLogRecord record) {
+            if (!(record instanceof VibrationRecord)) {
+                return false;
             }
-            if (mVibrationCount > 2) {
-                pw.println(
-                        "-> Skipping " + (mVibrationCount - 2) + " aggregated vibrations, latest:");
-            }
-            mLatestVibration.dumpCompact(pw);
+            Vibration.DebugInfo info = ((VibrationRecord) record).mInfo;
+            return mInfo.mCallerInfo.uid == info.mCallerInfo.uid
+                    && Objects.equals(mInfo.mCallerInfo.attrs, info.mCallerInfo.attrs)
+                    && Objects.equals(mInfo.mPlayedEffect, info.mPlayedEffect);
         }
 
-        synchronized void dump(ProtoOutputStream proto, long fieldId) {
-            mLatestVibration.dump(proto, fieldId);
+        @Override
+        public void dump(IndentingPrintWriter pw) {
+            // Prints a compact version of each vibration request for dumpsys.
+            mInfo.dumpCompact(pw);
+        }
+
+        @Override
+        public void dump(ProtoOutputStream proto, long fieldId) {
+            mInfo.dump(proto, fieldId);
         }
     }
 
@@ -2001,7 +1960,6 @@
 
         @Override
         public ExternalVibrationScale onExternalVibrationStart(ExternalVibration vib) {
-
             if (!hasExternalControlCapability()) {
                 return SCALE_MUTE;
             }
@@ -2085,10 +2043,9 @@
                 }
                 mCurrentExternalVibration = vibHolder;
                 vibHolder.linkToDeath();
-                vibHolder.scale.scaleLevel = mVibrationScaler.getExternalVibrationScaleLevel(
-                        attrs.getUsage());
-                vibHolder.scale.adaptiveHapticsScale = mVibrationScaler.getAdaptiveHapticsScale(
-                        attrs.getUsage());
+                vibHolder.scale.scaleLevel = mVibrationScaler.getScaleLevel(attrs.getUsage());
+                vibHolder.scale.adaptiveHapticsScale =
+                        mVibrationScaler.getAdaptiveHapticsScale(attrs.getUsage());
             }
 
             if (waitForCompletion) {
@@ -2300,7 +2257,7 @@
             HalVibration vib = performHapticFeedbackInternal(Binder.getCallingUid(),
                     Context.DEVICE_ID_DEFAULT, SHELL_PACKAGE_NAME, constant,
                     /* always= */ commonOptions.force, /* reason= */ commonOptions.description,
-                    deathBinder);
+                    deathBinder, false /* fromIme */);
             maybeWaitOnVibration(vib, commonOptions);
 
             return 0;
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java
index 37f3825..601c7f4 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java
@@ -357,15 +357,30 @@
      * Given some suggested crops, find cropHints for all orientations of the default display.
      */
     SparseArray<Rect> getDefaultCrops(SparseArray<Rect> suggestedCrops, Point bitmapSize) {
-        SparseArray<Rect> result = new SparseArray<>();
-        // add missing cropHints for all orientation of the default display
+
         SparseArray<Point> defaultDisplaySizes = mWallpaperDisplayHelper.getDefaultDisplaySizes();
         boolean rtl = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault())
                 == View.LAYOUT_DIRECTION_RTL;
+
+        // adjust existing entries for the default display
+        SparseArray<Rect> adjustedSuggestedCrops = new SparseArray<>();
         for (int i = 0; i < defaultDisplaySizes.size(); i++) {
             int orientation = defaultDisplaySizes.keyAt(i);
             Point displaySize = defaultDisplaySizes.valueAt(i);
-            Rect newCrop = getCrop(displaySize, bitmapSize, suggestedCrops, rtl);
+            Rect suggestedCrop = suggestedCrops.get(orientation);
+            if (suggestedCrop != null) {
+                adjustedSuggestedCrops.put(orientation,
+                        getCrop(displaySize, bitmapSize, suggestedCrops, rtl));
+            }
+        }
+
+        // add missing cropHints for all orientation of the default display
+        SparseArray<Rect> result = adjustedSuggestedCrops.clone();
+        for (int i = 0; i < defaultDisplaySizes.size(); i++) {
+            int orientation = defaultDisplaySizes.keyAt(i);
+            if (result.contains(orientation)) continue;
+            Point displaySize = defaultDisplaySizes.valueAt(i);
+            Rect newCrop = getCrop(displaySize, bitmapSize, adjustedSuggestedCrops, rtl);
             result.put(orientation, newCrop);
         }
         return result;
diff --git a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java
index 5f6ffd98..8742ab1 100644
--- a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java
+++ b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java
@@ -21,8 +21,8 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
+import android.app.ActivityOptions;
 import android.app.BroadcastOptions;
-import android.app.ComponentOptions;
 import android.app.PendingIntent;
 import android.app.ambientcontext.AmbientContextEvent;
 import android.app.wearable.IWearableSensingManager;
@@ -353,7 +353,7 @@
                             dataRequest);
                     BroadcastOptions options = BroadcastOptions.makeBasic();
                     options.setPendingIntentBackgroundActivityStartMode(
-                            ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED);
+                            ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED);
                     mDataRequestRateLimiter.noteEvent(
                             userId, RATE_LIMITER_PACKAGE_NAME, RATE_LIMITER_TAG);
                     final long previousCallingIdentity = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
index 596de68..1f9d265 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
@@ -96,6 +96,9 @@
     private boolean mWebViewPackageDirty = false;
     private boolean mAnyWebViewInstalled = false;
 
+    // Keeps track of whether we attempted to repair WebView before.
+    private boolean mAttemptedToRepairBefore = false;
+
     private static final int NUMBER_OF_RELROS_UNKNOWN = Integer.MAX_VALUE;
 
     // The WebView package currently in use (or the one we are preparing).
@@ -136,6 +139,7 @@
                 boolean removedOrChangedOldPackage = false;
                 String oldProviderName = null;
                 PackageInfo newPackage = null;
+                boolean repairNeeded = false;
                 synchronized (mLock) {
                     try {
                         newPackage = findPreferredWebViewPackage();
@@ -161,6 +165,7 @@
                         Slog.e(TAG, "Could not find valid WebView package to create relro with "
                                 + e);
                     }
+                    repairNeeded = shouldTriggerRepairLocked();
                 }
                 if (updateWebView && !removedOrChangedOldPackage
                         && oldProviderName != null) {
@@ -170,12 +175,18 @@
                     // only kills dependents of packages that are being removed.
                     mSystemInterface.killPackageDependents(oldProviderName);
                 }
+                if (repairNeeded) {
+                    attemptRepair();
+                }
                 return;
             }
         }
     }
 
     private boolean shouldTriggerRepairLocked() {
+        if (mAttemptedToRepairBefore) {
+            return false;
+        }
         if (mCurrentWebViewPackage == null) {
             return true;
         }
@@ -189,6 +200,26 @@
         }
     }
 
+    private void attemptRepair() {
+        // We didn't find a valid WebView implementation. Try explicitly re-installing and
+        // re-enabling the default package for all users in case it was disabled. If this actually
+        // changes the state, we will see the PackageManager broadcast shortly and try again.
+        synchronized (mLock) {
+            if (mAttemptedToRepairBefore) {
+                return;
+            }
+            mAttemptedToRepairBefore = true;
+        }
+        Slog.w(
+                TAG,
+                "No provider available for all users, trying to install and enable "
+                        + mDefaultProvider.packageName);
+        mSystemInterface.installExistingPackageForAllUsers(
+                mContext, mDefaultProvider.packageName);
+        mSystemInterface.enablePackageForAllUsers(
+                mContext, mDefaultProvider.packageName, true);
+    }
+
     @Override
     public void prepareWebViewInSystemServer() {
         try {
@@ -211,18 +242,7 @@
             }
 
             if (repairNeeded) {
-                // We didn't find a valid WebView implementation. Try explicitly re-installing and
-                // re-enabling the default package for all users in case it was disabled, even if we
-                // already did the one-time migration before. If this actually changes the state, we
-                // will see the PackageManager broadcast shortly and try again.
-                Slog.w(
-                        TAG,
-                        "No provider available for all users, trying to install and enable "
-                                + mDefaultProvider.packageName);
-                mSystemInterface.installExistingPackageForAllUsers(
-                        mContext, mDefaultProvider.packageName);
-                mSystemInterface.enablePackageForAllUsers(
-                        mContext, mDefaultProvider.packageName, true);
+                attemptRepair();
             }
 
         } catch (Throwable t) {
@@ -332,6 +352,7 @@
         PackageInfo oldPackage = null;
         PackageInfo newPackage = null;
         boolean providerChanged = false;
+        boolean repairNeeded = false;
         synchronized (mLock) {
             oldPackage = mCurrentWebViewPackage;
 
@@ -354,11 +375,19 @@
             if (providerChanged) {
                 onWebViewProviderChanged(newPackage);
             }
+            // Choosing another provider shouldn't break our state. Only check if repair
+            // is needed if this function is called as a result of a user change.
+            if (newProviderName == null) {
+                repairNeeded = shouldTriggerRepairLocked();
+            }
         }
         // Kill apps using the old provider only if we changed provider
         if (providerChanged && oldPackage != null) {
             mSystemInterface.killPackageDependents(oldPackage.packageName);
         }
+        if (repairNeeded) {
+            attemptRepair();
+        }
         // Return the new provider, this is not necessarily the one we were asked to switch to,
         // but the persistent setting will now be pointing to the provider we were asked to
         // switch to anyway.
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 44a0547..91eff18 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -304,9 +304,9 @@
     Surface forceShowMagnifierSurface(int displayId) {
         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
         if (displayMagnifier != null) {
-            displayMagnifier.mMagnifedViewport.mWindow.setAlpha(DisplayMagnifier.MagnifiedViewport
+            displayMagnifier.mMagnifiedViewport.mWindow.setAlpha(DisplayMagnifier.MagnifiedViewport
                     .ViewportWindow.AnimationController.MAX_ALPHA);
-            return displayMagnifier.mMagnifedViewport.mWindow.mSurface;
+            return displayMagnifier.mMagnifiedViewport.mWindow.mSurface;
         }
         return null;
     }
@@ -463,6 +463,10 @@
     }
 
     void drawMagnifiedRegionBorderIfNeeded(int displayId) {
+        if (Flags.magnificationAlwaysDrawFullscreenBorder()) {
+            return;
+        }
+
         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
             mAccessibilityTracing.logTrace(
                     TAG + ".drawMagnifiedRegionBorderIfNeeded",
@@ -614,7 +618,7 @@
 
         private final Context mDisplayContext;
         private final WindowManagerService mService;
-        private final MagnifiedViewport mMagnifedViewport;
+        private final MagnifiedViewport mMagnifiedViewport;
         private final Handler mHandler;
         private final DisplayContent mDisplayContent;
         private final Display mDisplay;
@@ -649,7 +653,8 @@
             mDisplayContent = displayContent;
             mDisplay = display;
             mHandler = new MyHandler(mService.mH.getLooper());
-            mMagnifedViewport = new MagnifiedViewport();
+            mMagnifiedViewport = Flags.magnificationAlwaysDrawFullscreenBorder()
+                    ? null : new MagnifiedViewport();
             mAccessibilityTracing =
                     AccessibilityController.getAccessibilityControllerInternal(mService);
             mLongAnimationDuration = mDisplayContext.getResources().getInteger(
@@ -692,7 +697,9 @@
                 mMagnificationSpec.clear();
             }
 
-            mMagnifedViewport.setShowMagnifiedBorderIfNeeded();
+            if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                mMagnifiedViewport.setShowMagnifiedBorderIfNeeded();
+            }
         }
 
         void setFullscreenMagnificationActivated(boolean activated) {
@@ -701,8 +708,10 @@
                         FLAGS_MAGNIFICATION_CALLBACK, "activated=" + activated);
             }
             mIsFullscreenMagnificationActivated = activated;
-            mMagnifedViewport.setMagnifiedRegionBorderShown(activated, true);
-            mMagnifedViewport.showMagnificationBoundsIfNeeded();
+            if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                mMagnifiedViewport.setMagnifiedRegionBorderShown(activated, true);
+                mMagnifiedViewport.showMagnificationBoundsIfNeeded();
+            }
         }
 
         boolean isFullscreenMagnificationActivated() {
@@ -737,7 +746,9 @@
             }
 
             recomputeBounds();
-            mMagnifedViewport.onDisplaySizeChanged();
+            if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                mMagnifiedViewport.onDisplaySizeChanged();
+            }
             mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED);
         }
 
@@ -806,14 +817,9 @@
             switch (transition) {
                 case WindowManagerPolicy.TRANSIT_ENTER:
                 case WindowManagerPolicy.TRANSIT_SHOW: {
-                    if (!isMagnifierActivated) {
+                    if (!isMagnifierActivated || !windowState.shouldMagnify()) {
                         break;
                     }
-                    if (Flags.doNotCheckIntersectionWhenNonMagnifiableWindowTransitions()) {
-                        if (!windowState.shouldMagnify()) {
-                            break;
-                        }
-                    }
                     switch (type) {
                         case WindowManager.LayoutParams.TYPE_APPLICATION:
                         case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION:
@@ -901,7 +907,10 @@
             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
                 mAccessibilityTracing.logTrace(LOG_TAG + ".destroy", FLAGS_MAGNIFICATION_CALLBACK);
             }
-            mMagnifedViewport.destroyWindow();
+
+            if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                mMagnifiedViewport.destroyWindow();
+            }
         }
 
         void drawMagnifiedRegionBorderIfNeeded() {
@@ -909,7 +918,10 @@
                 mAccessibilityTracing.logTrace(LOG_TAG + ".drawMagnifiedRegionBorderIfNeeded",
                         FLAGS_MAGNIFICATION_CALLBACK);
             }
-            mMagnifedViewport.drawWindowIfNeeded();
+
+            if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                mMagnifiedViewport.drawWindowIfNeeded();
+            }
         }
 
         void recomputeBounds() {
@@ -1006,14 +1018,16 @@
             }
             visibleWindows.clear();
 
-            mMagnifedViewport.intersectWithDrawBorderInset(screenWidth, screenHeight);
-
+            if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                mMagnifiedViewport.intersectWithDrawBorderInset(screenWidth, screenHeight);
+            }
 
             final boolean magnifiedChanged =
                     !mOldMagnificationRegion.equals(mMagnificationRegion);
             if (magnifiedChanged) {
-                mMagnifedViewport.updateBorderDrawingStatus(screenWidth, screenHeight);
-
+                if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                    mMagnifiedViewport.updateBorderDrawingStatus(screenWidth, screenHeight);
+                }
                 mOldMagnificationRegion.set(mMagnificationRegion);
                 final SomeArgs args = SomeArgs.obtain();
                 args.arg1 = Region.obtain(mMagnificationRegion);
@@ -1070,7 +1084,9 @@
         }
 
         void dump(PrintWriter pw, String prefix) {
-            mMagnifedViewport.dump(pw, prefix);
+            if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                mMagnifiedViewport.dump(pw, prefix);
+            }
         }
 
         private final class MagnifiedViewport {
@@ -1079,7 +1095,7 @@
             private final int mHalfBorderWidth;
             private final int mDrawBorderInset;
 
-            private final ViewportWindow mWindow;
+            @Nullable private final ViewportWindow mWindow;
 
             private boolean mFullRedrawNeeded;
 
@@ -1138,9 +1154,9 @@
             void onDisplaySizeChanged() {
                 // If fullscreen magnification is activated, hide the border immediately so
                 // the user does not see strange artifacts during display size changed caused by
-                // rotation or folding/unfolding the device. In the rotation case, the screenshot
-                // used for rotation already has the border. After the rotation is complete
-                // we will show the border.
+                // rotation or folding/unfolding the device. In the rotation case, the
+                // screenshot used for rotation already has the border. After the rotation is
+                // completed we will show the border.
                 if (isFullscreenMagnificationActivated()) {
                     setMagnifiedRegionBorderShown(false, false);
                     final long delay = (long) (mLongAnimationDuration
@@ -1173,6 +1189,8 @@
                 mWindow.dump(pw, prefix);
             }
 
+            // TODO(291891390): Remove this class when we clean up the flag
+            //  magnificationAlwaysDrawFullscreenBorder
             private final class ViewportWindow implements Runnable {
                 private static final String SURFACE_TITLE = "Magnification Overlay";
 
@@ -1467,6 +1485,9 @@
             public static final int MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED = 1;
             public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
             public static final int MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED = 4;
+
+            // TODO(291891390): Remove this field when we clean up the flag
+            //  magnificationAlwaysDrawFullscreenBorder
             public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
             public static final int MESSAGE_NOTIFY_IME_WINDOW_VISIBILITY_CHANGED = 6;
 
@@ -1495,7 +1516,9 @@
                     case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
                         synchronized (mService.mGlobalLock) {
                             if (isFullscreenMagnificationActivated()) {
-                                mMagnifedViewport.setMagnifiedRegionBorderShown(true, true);
+                                if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                                    mMagnifiedViewport.setMagnifiedRegionBorderShown(true, true);
+                                }
                                 mService.scheduleAnimationLocked();
                             }
                         }
diff --git a/services/core/java/com/android/server/wm/ActivityAssistInfo.java b/services/core/java/com/android/server/wm/ActivityAssistInfo.java
index 3b91780..2dc0046 100644
--- a/services/core/java/com/android/server/wm/ActivityAssistInfo.java
+++ b/services/core/java/com/android/server/wm/ActivityAssistInfo.java
@@ -30,12 +30,14 @@
     private final IBinder mAssistToken;
     private final int mTaskId;
     private final ComponentName mComponentName;
+    private final int mUserId;
 
     public ActivityAssistInfo(ActivityRecord activityRecord) {
         this.mActivityToken = activityRecord.token;
         this.mAssistToken = activityRecord.assistToken;
         this.mTaskId = activityRecord.getTask().mTaskId;
         this.mComponentName = activityRecord.mActivityComponent;
+        this.mUserId = activityRecord.mUserId;
     }
 
     /** @hide */
@@ -57,4 +59,9 @@
     public ComponentName getComponentName() {
         return mComponentName;
     }
+
+    /** @hide */
+    public int getUserId() {
+        return mUserId;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index ed5df5f..981c4c0 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -506,7 +506,8 @@
                     // keep backwards compatibility we remove the task from recents when finishing
                     // task with root activity.
                     mTaskSupervisor.removeTask(tr, false /*killProcess*/,
-                            finishWithRootActivity, "finish-activity", r.getUid(), r.info.name);
+                            finishWithRootActivity, "finish-activity", r.getUid(), r.getPid(),
+                            r.info.name);
                     res = true;
                     // Explicitly dismissing the activity so reset its relaunch flag.
                     r.mRelaunchReason = RELAUNCH_REASON_NONE;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index bc6f93f..d30a216 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -353,6 +353,7 @@
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManager.TransitionOldType;
 import android.view.animation.Animation;
+import android.window.ActivityWindowInfo;
 import android.window.ITaskFragmentOrganizer;
 import android.window.RemoteTransition;
 import android.window.SizeConfigurationBuckets;
@@ -519,6 +520,7 @@
     private int mLastReportedDisplayId;
     boolean mLastReportedMultiWindowMode;
     boolean mLastReportedPictureInPictureMode;
+    private final ActivityWindowInfo mLastReportedActivityWindowInfo = new ActivityWindowInfo();
     ActivityRecord resultTo; // who started this entry, so will get our reply
     final String resultWho; // additional identifier for use by resultTo.
     final int requestCode;  // code given by requester (resultTo)
@@ -551,7 +553,6 @@
     boolean launchFailed;   // set if a launched failed, to abort on 2nd try
     boolean delayedResume;  // not yet resumed because of stopped app switches?
     boolean finishing;      // activity in pending finish list?
-    int configChangeFlags;  // which config values have changed
     private boolean keysPaused;     // has key dispatching been paused for it?
     int launchMode;         // the launch mode activity attribute.
     int lockTaskLaunchMode; // the lockTaskMode manifest attribute, subject to override
@@ -958,6 +959,7 @@
      */
     private final Configuration mTmpConfig = new Configuration();
     private final Rect mTmpBounds = new Rect();
+    private final ActivityWindowInfo mTmpActivityWindowInfo = new ActivityWindowInfo();
 
     // Token for targeting this activity for assist purposes.
     final Binder assistToken = new Binder();
@@ -1096,6 +1098,12 @@
         pw.println(prefix + "mLastReportedConfigurations:");
         mLastReportedConfiguration.dump(pw, prefix + "  ");
 
+        if (Flags.activityWindowInfoFlag()) {
+            pw.print(prefix);
+            pw.print("mLastReportedActivityWindowInfo=");
+            pw.println(mLastReportedActivityWindowInfo);
+        }
+
         pw.print(prefix); pw.print("CurrentConfiguration="); pw.println(getConfiguration());
         if (!getRequestedOverrideConfiguration().equals(EMPTY)) {
             pw.println(prefix + "RequestedOverrideConfiguration="
@@ -1286,10 +1294,6 @@
         if (mDeferHidingClient) {
             pw.println(prefix + "mDeferHidingClient=" + mDeferHidingClient);
         }
-        if (configChangeFlags != 0) {
-            pw.print(prefix); pw.print(" configChangeFlags=");
-                    pw.println(Integer.toHexString(configChangeFlags));
-        }
         if (mServiceConnectionsHolder != null) {
             pw.print(prefix); pw.print("connections="); pw.println(mServiceConnectionsHolder);
         }
@@ -1447,7 +1451,8 @@
         mSizeConfigurations = sizeConfigurations;
     }
 
-    private void scheduleActivityMovedToDisplay(int displayId, Configuration config) {
+    private void scheduleActivityMovedToDisplay(int displayId, @NonNull Configuration config,
+            @NonNull ActivityWindowInfo activityWindowInfo) {
         if (!attachedToProcess()) {
             ProtoLog.w(WM_DEBUG_SWITCH, "Can't report activity moved "
                     + "to display - client not running, activityRecord=%s, displayId=%d",
@@ -1460,13 +1465,14 @@
                     config);
 
             mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
-                    MoveToDisplayItem.obtain(token, displayId, config));
+                    MoveToDisplayItem.obtain(token, displayId, config, activityWindowInfo));
         } catch (RemoteException e) {
             // If process died, whatever.
         }
     }
 
-    private void scheduleConfigurationChanged(Configuration config) {
+    private void scheduleConfigurationChanged(@NonNull Configuration config,
+            @NonNull ActivityWindowInfo activityWindowInfo) {
         if (!attachedToProcess()) {
             ProtoLog.w(WM_DEBUG_CONFIGURATION, "Can't report activity configuration "
                     + "update - client not running, activityRecord=%s", this);
@@ -1477,7 +1483,7 @@
                     + "config: %s", this, config);
 
             mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
-                    ActivityConfigurationChangeItem.obtain(token, config));
+                    ActivityConfigurationChangeItem.obtain(token, config, activityWindowInfo));
         } catch (RemoteException e) {
             // If process died, whatever.
         }
@@ -2883,6 +2889,11 @@
 
     /** Makes starting window always fill the associated task. */
     private void attachStartingSurfaceToAssociatedTask() {
+        if (mSyncState == SYNC_STATE_NONE && isEmbedded()) {
+            // Collect this activity since it's starting window will reparent to task. To ensure
+            // any starting window's transaction will occur in order.
+            mTransitionController.collect(this);
+        }
         // Associate the configuration of starting window with the task.
         overrideConfigurationPropagation(mStartingWindow, mStartingData.mAssociatedTask);
         getSyncTransaction().reparent(mStartingWindow.mSurfaceControl,
@@ -3150,6 +3161,30 @@
         }
     }
 
+    /**
+     * This is different from {@link #isEmbedded()}.
+     * {@link #isEmbedded()} is {@code true} when any of the parent {@link TaskFragment} is created
+     * by a {@link android.window.TaskFragmentOrganizer}, while this method is {@code true} when
+     * the parent {@link TaskFragment} is embedded and has bounds override that does not fill the
+     * leaf {@link Task}.
+     */
+    boolean isEmbeddedInHostContainer() {
+        final TaskFragment taskFragment = getOrganizedTaskFragment();
+        return taskFragment != null && taskFragment.isEmbeddedWithBoundsOverride();
+    }
+
+    @NonNull
+    ActivityWindowInfo getActivityWindowInfo() {
+        if (!Flags.activityWindowInfoFlag() || !isAttached()) {
+            return mTmpActivityWindowInfo;
+        }
+        mTmpActivityWindowInfo.set(
+                isEmbeddedInHostContainer(),
+                getTask().getBounds(),
+                getTaskFragment().getBounds());
+        return mTmpActivityWindowInfo;
+    }
+
     @Override
     @Nullable
     TaskDisplayArea getDisplayArea() {
@@ -4024,7 +4059,7 @@
             try {
                 if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + this);
                 mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
-                        DestroyActivityItem.obtain(token, finishing, configChangeFlags));
+                        DestroyActivityItem.obtain(token, finishing));
             } catch (Exception e) {
                 // We can just ignore exceptions here...  if the process has crashed, our death
                 // notification will clean things up.
@@ -4066,8 +4101,6 @@
             }
         }
 
-        configChangeFlags = 0;
-
         return removedFromHistory;
     }
 
@@ -4986,7 +5019,7 @@
                 return PauseActivityItem.obtain(token);
             case STOPPING:
             case STOPPED:
-                return StopActivityItem.obtain(token, configChangeFlags);
+                return StopActivityItem.obtain(token);
             default:
                 // Do not send a result immediately if the activity is in state INITIALIZING,
                 // RESTARTING_PROCESS, FINISHING, DESTROYING, or DESTROYED.
@@ -6260,7 +6293,7 @@
             try {
                 mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
                         PauseActivityItem.obtain(token, finishing, false /* userLeaving */,
-                                configChangeFlags, false /* dontReport */, mAutoEnteringPip));
+                                false /* dontReport */, mAutoEnteringPip));
             } catch (Exception e) {
                 Slog.w(TAG, "Exception thrown sending pause: " + intent.getComponent(), e);
             }
@@ -6574,7 +6607,7 @@
             EventLogTags.writeWmStopActivity(
                     mUserId, System.identityHashCode(this), shortComponentName);
             mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
-                    StopActivityItem.obtain(token, configChangeFlags));
+                    StopActivityItem.obtain(token));
 
             mAtmService.mH.postDelayed(mStopTimeoutRunnable, STOP_TIMEOUT);
         } catch (Exception e) {
@@ -6832,6 +6865,7 @@
         // stop tracking
         mSplashScreenStyleSolidColor = true;
 
+        mAtmService.mBackNavigationController.removePredictiveSurfaceIfNeeded(this);
         if (mStartingWindow != null) {
             ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Finish starting %s"
                     + ": first real window is shown, no animation", win.mToken);
@@ -8213,6 +8247,12 @@
         mLastReportedConfiguration.setConfiguration(global, override);
     }
 
+    void setLastReportedActivityWindowInfo(@NonNull ActivityWindowInfo activityWindowInfo) {
+        if (Flags.activityWindowInfoFlag()) {
+            mLastReportedActivityWindowInfo.set(activityWindowInfo);
+        }
+    }
+
     @Nullable
     CompatDisplayInsets getCompatDisplayInsets() {
         if (mLetterboxUiController.hasInheritedLetterboxBehavior()) {
@@ -9745,7 +9785,11 @@
         // configurations because there are cases (like moving a task to the root pinned task) where
         // the combine configurations are equal, but would otherwise differ in the override config
         mTmpConfig.setTo(mLastReportedConfiguration.getMergedConfiguration());
-        if (getConfiguration().equals(mTmpConfig) && !displayChanged) {
+        final ActivityWindowInfo newActivityWindowInfo = getActivityWindowInfo();
+        final boolean isActivityWindowInfoChanged = Flags.activityWindowInfoFlag()
+                && !mLastReportedActivityWindowInfo.equals(newActivityWindowInfo);
+        if (!displayChanged && !isActivityWindowInfoChanged
+                && getConfiguration().equals(mTmpConfig)) {
             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration & display "
                     + "unchanged in %s", this);
             return true;
@@ -9762,6 +9806,7 @@
         final Configuration newMergedOverrideConfig = getMergedOverrideConfiguration();
 
         setLastReportedConfiguration(getProcessGlobalConfiguration(), newMergedOverrideConfig);
+        setLastReportedActivityWindowInfo(newActivityWindowInfo);
 
         if (mState == INITIALIZING) {
             // No need to relaunch or schedule new config for activity that hasn't been launched
@@ -9778,9 +9823,10 @@
             // There are no significant differences, so we won't relaunch but should still deliver
             // the new configuration to the client process.
             if (displayChanged) {
-                scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig);
+                scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig,
+                        newActivityWindowInfo);
             } else {
-                scheduleConfigurationChanged(newMergedOverrideConfig);
+                scheduleConfigurationChanged(newMergedOverrideConfig, newActivityWindowInfo);
             }
             notifyDisplayCompatPolicyAboutConfigurationChange(
                     mLastReportedConfiguration.getMergedConfiguration(), mTmpConfig);
@@ -9805,7 +9851,6 @@
 
         if (shouldRelaunchLocked(changes, mTmpConfig)) {
             // Aha, the activity isn't handling the change, so DIE DIE DIE.
-            configChangeFlags |= changes;
             if (mVisible && mAtmService.mTmpUpdateConfigurationResult.mIsUpdating
                     && !mTransitionController.isShellTransitionsEnabled()) {
                 startFreezingScreenLocked(app, mAtmService.mTmpUpdateConfigurationResult.changes);
@@ -9834,7 +9879,7 @@
                 ProtoLog.v(WM_DEBUG_STATES, "Config is relaunching invisible "
                         + "activity %s called by %s", this, Debug.getCallers(4));
             }
-            relaunchActivityLocked(preserveWindow);
+            relaunchActivityLocked(preserveWindow, changes);
 
             // All done...  tell the caller we weren't able to keep this activity around.
             return false;
@@ -9845,9 +9890,10 @@
         // changes is always sent to all processes when they happen so it can just use whatever
         // system level configuration it last got.
         if (displayChanged) {
-            scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig);
+            scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig,
+                    newActivityWindowInfo);
         } else {
-            scheduleConfigurationChanged(newMergedOverrideConfig);
+            scheduleConfigurationChanged(newMergedOverrideConfig, newActivityWindowInfo);
         }
         notifyDisplayCompatPolicyAboutConfigurationChange(
                 mLastReportedConfiguration.getMergedConfiguration(), mTmpConfig);
@@ -9975,9 +10021,8 @@
                 | CONFIG_SCREEN_LAYOUT)) != 0;
     }
 
-    void relaunchActivityLocked(boolean preserveWindow) {
+    void relaunchActivityLocked(boolean preserveWindow, int configChangeFlags) {
         if (mAtmService.mSuppressResizeConfigChanges && preserveWindow) {
-            configChangeFlags = 0;
             return;
         }
         if (!preserveWindow) {
@@ -10020,7 +10065,7 @@
                     pendingResults, pendingNewIntents, configChangeFlags,
                     new MergedConfiguration(getProcessGlobalConfiguration(),
                             getMergedOverrideConfiguration()),
-                    preserveWindow);
+                    preserveWindow, getActivityWindowInfo());
             final ActivityLifecycleItem lifecycleItem;
             if (andResume) {
                 lifecycleItem = ResumeActivityItem.obtain(token, isTransitionForward(),
@@ -10050,8 +10095,6 @@
 
         // The activity may be waiting for stop, but that is no longer appropriate for it.
         mTaskSupervisor.mStoppingActivities.remove(this);
-
-        configChangeFlags = 0;
     }
 
     /**
@@ -10120,7 +10163,7 @@
         // {@link ActivityTaskManagerService.activityStopped}).
         try {
             mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
-                    StopActivityItem.obtain(token, 0 /* configChanges */));
+                    StopActivityItem.obtain(token));
         } catch (RemoteException e) {
             Slog.w(TAG, "Exception thrown during restart " + this, e);
         }
diff --git a/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java b/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java
index 01d077a..4149bd9 100644
--- a/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java
+++ b/services/core/java/com/android/server/wm/ActivitySecurityModelFeatureFlags.java
@@ -41,7 +41,7 @@
     static final String DOC_LINK = "go/android-asm";
 
     /** Used to determine which version of the ASM logic was used in logs while we iterate */
-    static final int ASM_VERSION = 9;
+    static final int ASM_VERSION = 10;
 
     private static final String NAMESPACE = NAMESPACE_WINDOW_MANAGER;
     private static final String KEY_ASM_PREFIX = "ActivitySecurity__";
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 066d262..6ad056f 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1548,6 +1548,8 @@
                 result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
                         startFlags, options, inTask, inTaskFragment, balVerdict,
                         intentGrants, realCallingUid);
+            } catch (Exception ex) {
+                Slog.e(TAG, "Exception on startActivityInner", ex);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
                 startedActivityRootTask = handleStartResult(r, options, result, newTransition,
@@ -2087,7 +2089,7 @@
 
         if (!mSupervisor.getBackgroundActivityLaunchController().checkActivityAllowedToStart(
                 mSourceRecord, r, newTask, avoidMoveToFront(), targetTask, mLaunchFlags, mBalCode,
-                mCallingUid, mRealCallingUid)) {
+                mCallingUid, mRealCallingUid, mPreferredTaskDisplayArea)) {
             return START_ABORTED;
         }
 
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 4a5b221..c088118 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -822,4 +822,7 @@
      */
     public abstract void unregisterCompatScaleProvider(
             @CompatScaleProvider.CompatScaleModeOrderId int id);
+
+    /** Returns whether assist data is allowed. */
+    public abstract boolean isAssistDataAllowed();
 }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 24c8ebb..e283f3e 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2505,6 +2505,11 @@
         userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId, "getRecentTasks");
         final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(),
                 callingUid);
+        if (!mAmInternal.isUserRunning(userId, ActivityManager.FLAG_AND_UNLOCKED)) {
+            Slog.i(TAG, "User " + userId + " is locked. Cannot load recents");
+            return ParceledListSlice.emptyList();
+        }
+        mRecentTasks.loadRecentTasksIfNeeded(userId);
         synchronized (mGlobalLock) {
             return mRecentTasks.getRecentTasks(maxNum, flags, allowed, userId, callingUid);
         }
@@ -4158,19 +4163,21 @@
     @Override
     public void onPictureInPictureUiStateChanged(PictureInPictureUiState pipState) {
         enforceTaskPermission("onPictureInPictureUiStateChanged");
-        // The PictureInPictureUiState is sent to current pip task if there is any
-        // -or- the top standard task (state like entering PiP does not require a pinned task).
-        final Task task;
-        if (mRootWindowContainer.getDefaultTaskDisplayArea().hasPinnedTask()) {
-            task = mRootWindowContainer.getDefaultTaskDisplayArea().getRootPinnedTask();
-        } else {
-            task = mRootWindowContainer.getDefaultTaskDisplayArea().getRootTask(
-                    t -> t.isActivityTypeStandard());
-        }
-        if (task != null && task.getTopMostActivity() != null
-                && !task.getTopMostActivity().isState(FINISHING, DESTROYING, DESTROYED)) {
-            mWindowManager.mAtmService.mActivityClientController.onPictureInPictureUiStateChanged(
-                    task.getTopMostActivity(), pipState);
+        synchronized (mGlobalLock) {
+            // The PictureInPictureUiState is sent to current pip task if there is any
+            // -or- the top standard task (state like entering PiP does not require a pinned task).
+            final Task task;
+            if (mRootWindowContainer.getDefaultTaskDisplayArea().hasPinnedTask()) {
+                task = mRootWindowContainer.getDefaultTaskDisplayArea().getRootPinnedTask();
+            } else {
+                task = mRootWindowContainer.getDefaultTaskDisplayArea().getRootTask(
+                        t -> t.isActivityTypeStandard());
+            }
+            if (task != null && task.getTopMostActivity() != null
+                    && !task.getTopMostActivity().isState(FINISHING, DESTROYING, DESTROYED)) {
+                mWindowManager.mAtmService.mActivityClientController
+                        .onPictureInPictureUiStateChanged(task.getTopMostActivity(), pipState);
+            }
         }
     }
 
@@ -6018,6 +6025,10 @@
         public int startActivityWithScreenshot(@NonNull Intent intent,
                 @NonNull String callingPackage, int callingUid, int callingPid,
                 @Nullable IBinder resultTo, @Nullable Bundle options, int userId) {
+            userId = getActivityStartController().checkTargetUser(userId,
+                    false /* validateIncomingUser */, Binder.getCallingPid(),
+                    Binder.getCallingUid(), "startActivityWithScreenshot");
+
             return getActivityStartController()
                     .obtainStarter(intent, "startActivityWithScreenshot")
                     .setCallingUid(callingUid)
@@ -7056,11 +7067,9 @@
 
         @Override
         public void loadRecentTasksForUser(int userId) {
-            synchronized (mGlobalLock) {
-                mRecentTasks.loadUserRecentsLocked(userId);
-                // TODO renaming the methods(?)
-                mPackageConfigPersister.loadUserPackages(userId);
-            }
+            // This runs on android.fg thread when the user is unlocking.
+            mRecentTasks.loadRecentTasksIfNeeded(userId);
+            mPackageConfigPersister.loadUserPackages(userId);
         }
 
         @Override
@@ -7344,6 +7353,11 @@
                 @CompatScaleProvider.CompatScaleModeOrderId int id) {
             ActivityTaskManagerService.this.unregisterCompatScaleProvider(id);
         }
+
+        @Override
+        public boolean isAssistDataAllowed() {
+            return ActivityTaskManagerService.this.isAssistDataAllowed();
+        }
     }
 
     static boolean isPip2ExperimentEnabled() {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 09f5eda..2cda1f5 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -42,6 +42,7 @@
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
+import static android.os.Process.INVALID_PID;
 import static android.os.Process.INVALID_UID;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
@@ -73,6 +74,7 @@
 import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
 import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_SUPERVISOR_TASK_MSG;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+import static com.android.server.wm.ClientLifecycleManager.shouldDispatchCompatClientTransactionIndependently;
 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_ALLOWLISTED;
 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE;
 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
@@ -138,6 +140,7 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.view.Display;
+import android.window.ActivityWindowInfo;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -909,6 +912,9 @@
                 final Configuration overrideConfig = r.getMergedOverrideConfiguration();
                 r.setLastReportedConfiguration(procConfig, overrideConfig);
 
+                final ActivityWindowInfo activityWindowInfo = r.getActivityWindowInfo();
+                r.setLastReportedActivityWindowInfo(activityWindowInfo);
+
                 logIfTransactionTooLarge(r.intent, r.getSavedState());
 
                 final TaskFragment organizedTaskFragment = r.getOrganizedTaskFragment();
@@ -931,7 +937,7 @@
                         results, newIntents, r.takeSceneTransitionInfo(), isTransitionForward,
                         proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
                         r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken,
-                        r.initialCallerInfoAccessToken);
+                        r.initialCallerInfoAccessToken, activityWindowInfo);
 
                 // Set desired final state.
                 final ActivityLifecycleItem lifecycleItem;
@@ -943,6 +949,13 @@
                 }
 
                 // Schedule transaction.
+                if (shouldDispatchCompatClientTransactionIndependently(r.mTargetSdk)) {
+                    // LaunchActivityItem has @UnsupportedAppUsage usages.
+                    // Guard the bundleClientTransactionFlag feature with targetSDK on Android 15+.
+                    // To not bundle the transaction, dispatch the pending before schedule new
+                    // transaction.
+                    mService.getLifecycleManager().dispatchPendingTransaction(proc.getThread());
+                }
                 mService.getLifecycleManager().scheduleTransactionAndLifecycleItems(
                         proc.getThread(), launchActivityItem, lifecycleItem,
                         // Immediately dispatch the transaction, so that if it fails, the server can
@@ -1648,11 +1661,11 @@
      * @return Returns true if the given task was found and removed.
      */
     boolean removeTaskById(int taskId, boolean killProcess, boolean removeFromRecents,
-            String reason, int callingUid) {
+            String reason, int callingUid, int callingPid) {
         final Task task =
                 mRootWindowContainer.anyTaskForId(taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
         if (task != null) {
-            removeTask(task, killProcess, removeFromRecents, reason, callingUid, null);
+            removeTask(task, killProcess, removeFromRecents, reason, callingUid, callingPid, null);
             return true;
         }
         Slog.w(TAG, "Request to remove task ignored for non-existent task " + taskId);
@@ -1660,11 +1673,11 @@
     }
 
     void removeTask(Task task, boolean killProcess, boolean removeFromRecents, String reason) {
-        removeTask(task, killProcess, removeFromRecents, reason, SYSTEM_UID, null);
+        removeTask(task, killProcess, removeFromRecents, reason, SYSTEM_UID, INVALID_PID, null);
     }
 
     void removeTask(Task task, boolean killProcess, boolean removeFromRecents, String reason,
-            int callingUid, String callerActivityClassName) {
+            int callingUid, int callingPid, String callerActivityClassName) {
         if (task.mInRemoveTask) {
             // Prevent recursion.
             return;
@@ -1701,8 +1714,8 @@
             if (task.isPersistable) {
                 mService.notifyTaskPersisterLocked(null, true);
             }
-            mBalController
-                    .checkActivityAllowedToClearTask(task, callingUid, callerActivityClassName);
+            mBalController.checkActivityAllowedToClearTask(
+                            task, callingUid, callingPid, callerActivityClassName);
         } finally {
             task.mInRemoveTask = false;
         }
@@ -1870,7 +1883,7 @@
             // Task was trimmed from the recent tasks list -- remove the active task record as well
             // since the user won't really be able to go back to it
             removeTaskById(task.mTaskId, killProcess, false /* removeFromRecents */,
-                    "recent-task-trimmed", SYSTEM_UID);
+                    "recent-task-trimmed", SYSTEM_UID, INVALID_PID);
         }
         task.removedFromRecents();
     }
@@ -1889,7 +1902,7 @@
         // Check that we aren't reparenting to the same root task that the task is already in
         if (prevRootTask != null && prevRootTask.mTaskId == rootTaskId) {
             Slog.w(TAG, "Can not reparent to same root task, task=" + task
-                    + " already in rootTaskId=" + rootTaskId);
+                    + " already in rootTaskId=" + rootTaskId + " by " + Debug.getCallers(8));
             return prevRootTask;
         }
 
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 50de0b0..d699af8 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -77,11 +77,13 @@
 
         synchronized (mService.mGlobalLock) {
             int origCallingUid = Binder.getCallingUid();
+            int origCallingPid = Binder.getCallingPid();
             final long callingIdentity = Binder.clearCallingIdentity();
             try {
                 // We remove the task from recents to preserve backwards
                 if (!mService.mTaskSupervisor.removeTaskById(mTaskId, false,
-                        REMOVE_FROM_RECENTS, "finish-and-remove-task", origCallingUid)) {
+                        REMOVE_FROM_RECENTS, "finish-and-remove-task", origCallingUid,
+                        origCallingPid)) {
                     throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
                 }
             } finally {
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 939cf1a..1a63f14 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -137,7 +137,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.TransitionAnimation;
-import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.DumpUtils.Dump;
 import com.android.internal.util.function.pooled.PooledLambda;
@@ -248,7 +247,7 @@
         mHandler = new Handler(service.mH.getLooper());
         mDisplayContent = displayContent;
         mTransitionAnimation = new TransitionAnimation(
-                context, ProtoLogImpl.isEnabled(WM_DEBUG_ANIM), TAG);
+                context, ProtoLog.isEnabled(WM_DEBUG_ANIM), TAG);
 
         mGridLayoutRecentsEnabled = SystemProperties.getBoolean("ro.recents.grid", false);
 
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index b51f899..e155126 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -61,6 +61,7 @@
 import com.android.internal.policy.TransitionAnimation;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.server.wm.utils.InsetUtils;
+import com.android.window.flags.Flags;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -644,6 +645,10 @@
         return false;
     }
 
+    void removePredictiveSurfaceIfNeeded(ActivityRecord openActivity) {
+        mAnimationHandler.markWindowHasDrawn(openActivity);
+    }
+
     private class NavigationMonitor {
         // The window which triggering the back navigation.
         private WindowState mNavigatingWindow;
@@ -897,7 +902,8 @@
             mWindowManagerService = wms;
             final Context context = wms.mContext;
             mShowWindowlessSurface = context.getResources().getBoolean(
-                    com.android.internal.R.bool.config_predictShowStartingSurface);
+                    com.android.internal.R.bool.config_predictShowStartingSurface)
+                    && Flags.activitySnapshotByDefault();
         }
         private static final int UNKNOWN = 0;
         private static final int TASK_SWITCH = 1;
@@ -1032,6 +1038,23 @@
             return isAnimateTarget(wc, mCloseAdaptor.mTarget, mSwitchType);
         }
 
+        void markWindowHasDrawn(ActivityRecord activity) {
+            if (!mComposed || mWaitTransition) {
+                return;
+            }
+            boolean allWindowDrawn = true;
+            for (int i = mOpenAnimAdaptor.mAdaptors.length - 1; i >= 0; --i) {
+                final BackWindowAnimationAdaptor next = mOpenAnimAdaptor.mAdaptors[i];
+                if (isAnimateTarget(activity, next.mTarget, mSwitchType)) {
+                    next.mAppWindowDrawn = true;
+                }
+                allWindowDrawn &= next.mAppWindowDrawn;
+            }
+            if (allWindowDrawn) {
+                mOpenAnimAdaptor.cleanUpWindowlessSurface(true);
+            }
+        }
+
         private static boolean isAnimateTarget(@NonNull WindowContainer window,
                 @NonNull WindowContainer animationTarget, int switchType) {
             if (switchType == TASK_SWITCH) {
@@ -1134,15 +1157,17 @@
             final BackWindowAnimationAdaptor adaptor =
                     new BackWindowAnimationAdaptor(target, isOpen, switchType);
             final SurfaceControl.Transaction pt = target.getPendingTransaction();
-            target.startAnimation(pt, adaptor, false /* hidden */, ANIMATION_TYPE_PREDICT_BACK);
             // Workaround to show TaskFragment which can be hide in Transitions and won't show
             // during isAnimating.
             if (isOpen && target.asActivityRecord() != null) {
                 final TaskFragment fragment = target.asActivityRecord().getTaskFragment();
                 if (fragment != null) {
+                    // Ensure task fragment surface has updated, in case configuration has changed.
+                    fragment.updateOrganizedTaskFragmentSurface();
                     pt.show(fragment.mSurfaceControl);
                 }
             }
+            target.startAnimation(pt, adaptor, false /* hidden */, ANIMATION_TYPE_PREDICT_BACK);
             return adaptor;
         }
 
@@ -1181,8 +1206,6 @@
                 for (int i = mAdaptors.length - 1; i >= 0; --i) {
                     mAdaptors[i].mTarget.cancelAnimation();
                 }
-                mRequestedStartingSurfaceId = INVALID_TASK_ID;
-                mStartingSurface = null;
                 if (mCloseTransaction != null) {
                     mCloseTransaction.apply();
                     mCloseTransaction = null;
@@ -1235,7 +1258,7 @@
                         represent.allowEnterPip);
             }
 
-            void createStartingSurface(ActivityRecord[] visibleOpenActivities) {
+            void createStartingSurface(@Nullable TaskSnapshot snapshot) {
                 if (mAdaptors[0].mSwitchType == DIALOG_CLOSE) {
                     return;
                 }
@@ -1253,7 +1276,6 @@
                 if (mainActivity == null) {
                     return;
                 }
-                final TaskSnapshot snapshot = getSnapshot(mainOpen, visibleOpenActivities);
                 // If there is only one adaptor, attach the windowless window to top activity,
                 // because fixed rotation only applies on activity.
                 // Note that embedded activity won't use fixed rotation.
@@ -1321,11 +1343,13 @@
                         .removeWindowlessStartingSurface(mRequestedStartingSurfaceId,
                                 !openTransitionMatch);
                 mRequestedStartingSurfaceId = INVALID_TASK_ID;
+                mStartingSurface = null;
             }
         }
 
         private static class BackWindowAnimationAdaptor implements AnimationAdapter {
             SurfaceControl mCapturedLeash;
+            boolean mAppWindowDrawn;
             private final Rect mBounds = new Rect();
             private final WindowContainer mTarget;
             private final boolean mIsOpen;
@@ -1507,9 +1531,16 @@
             private void applyPreviewStrategy(
                     @NonNull BackWindowAnimationAdaptorWrapper openAnimationAdaptor,
                     @NonNull ActivityRecord[] visibleOpenActivities) {
+                boolean needsLaunchBehind = true;
                 if (isSupportWindowlessSurface() && mShowWindowlessSurface && !mIsLaunchBehind) {
-                    openAnimationAdaptor.createStartingSurface(visibleOpenActivities);
-                } else {
+                    final WindowContainer mainOpen = openAnimationAdaptor.mAdaptors[0].mTarget;
+                    final TaskSnapshot snapshot = getSnapshot(mainOpen, visibleOpenActivities);
+                    openAnimationAdaptor.createStartingSurface(snapshot);
+                    // set LaunchBehind if we are creating splash screen surface.
+                    needsLaunchBehind = snapshot == null
+                            && openAnimationAdaptor.mRequestedStartingSurfaceId != INVALID_TASK_ID;
+                }
+                if (needsLaunchBehind) {
                     for (int i = visibleOpenActivities.length - 1; i >= 0; --i) {
                         setLaunchBehind(visibleOpenActivities[i]);
                     }
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index fdae53f..071f403 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -21,13 +21,16 @@
 import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
 import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
 import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
-import static android.app.ComponentOptions.BackgroundActivityStartMode;
+import static android.app.ActivityOptions.BackgroundActivityStartMode;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+import static android.os.Process.INVALID_PID;
+import static android.os.Process.INVALID_UID;
 import static android.os.Process.SYSTEM_UID;
 import static android.provider.DeviceConfig.NAMESPACE_WINDOW_MANAGER;
 
+import static com.android.server.wm.ActivityStarter.ASM_RESTRICTIONS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -67,6 +70,7 @@
 import android.util.Slog;
 import android.widget.Toast;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FrameworkStatsLog;
@@ -75,6 +79,7 @@
 import com.android.server.am.PendingIntentRecord;
 
 import java.lang.annotation.Retention;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.StringJoiner;
 import java.util.function.Consumer;
@@ -1022,7 +1027,7 @@
     }
 
     /**
-     * Log activity starts which violate one of the following rules of the
+     * Check activity starts which violate one of the following rules of the
      * activity security model (ASM):
      * See go/activity-security for rationale behind the rules.
      * 1. Within a task, only an activity matching a top UID of the task can start activities
@@ -1032,7 +1037,7 @@
     boolean checkActivityAllowedToStart(@Nullable ActivityRecord sourceRecord,
             @NonNull ActivityRecord targetRecord, boolean newTask, boolean avoidMoveTaskToFront,
             @Nullable Task targetTask, int launchFlags, int balCode, int callingUid,
-            int realCallingUid) {
+            int realCallingUid, TaskDisplayArea preferredTaskDisplayArea) {
         // BAL Exception allowed in all cases
         if (balCode == BAL_ALLOW_ALLOWLISTED_UID) {
             return true;
@@ -1055,68 +1060,46 @@
             }
         }
 
-        if (balCode == BAL_ALLOW_GRACE_PERIOD) {
-            // Allow if launching into new task, and caller matches most recently finished activity
-            if (taskToFront && mTopFinishedActivity != null
-                    && mTopFinishedActivity.mUid == callingUid) {
-                return true;
-            }
-
-            // Launching into existing task - allow if matches most recently finished activity
-            // within the task.
-            // We can reach here multiple ways:
-            // 1. activity in fg fires intent (taskToFront = false, sourceRecord is available)
-            // 2. activity in bg fires intent (taskToFront = false, sourceRecord is available)
-            // 3. activity in bg fires intent with NEW_FLAG (taskToFront = true,
-            //         avoidMoveTaskToFront = true, sourceRecord is available)
-            // 4. activity in bg fires PI (taskToFront = true, avoidMoveTaskToFront = true,
-            //         sourceRecord is not available, targetTask may be available)
-            if (!taskToFront || avoidMoveTaskToFront) {
-                if (targetTask != null) {
-                    FinishedActivityEntry finishedEntry =
-                            mTaskIdToFinishedActivity.get(targetTask.mTaskId);
-                    if (finishedEntry != null && finishedEntry.mUid == callingUid) {
-                        return true;
-                    }
-                }
-
-                if (sourceRecord != null) {
-                    FinishedActivityEntry finishedEntry =
-                            mTaskIdToFinishedActivity.get(sourceRecord.getTask().mTaskId);
-                    if (finishedEntry != null && finishedEntry.mUid == callingUid) {
-                        return true;
-                    }
-                }
-            }
-        }
-
-        BlockActivityStart bas = null;
+        BlockActivityStart bas = new BlockActivityStart();
         if (sourceRecord != null) {
-            boolean passesAsmChecks = true;
             Task sourceTask = sourceRecord.getTask();
 
+            Task taskToCheck = taskToFront ? sourceTask : targetTask;
+            bas = checkTopActivityForAsm(taskToCheck, sourceRecord.getUid(),
+                    sourceRecord, bas);
+
             // Allow launching into a new task (or a task matching the launched activity's
             // affinity) only if the current task is foreground or mutating its own task.
             // The latter can happen eg. if caller uses NEW_TASK flag and the activity being
             // launched matches affinity of source task.
-            if (taskToFront) {
-                passesAsmChecks = sourceTask != null
-                        && (sourceTask.isVisible() || sourceTask == targetTask);
-            }
-
-            if (passesAsmChecks) {
-                Task taskToCheck = taskToFront ? sourceTask : targetTask;
-                bas = isTopActivityMatchingUidAbsentForAsm(taskToCheck, sourceRecord.getUid(),
-                        sourceRecord);
+            if (taskToFront && bas.mTopActivityMatchesSource) {
+                bas.mTopActivityMatchesSource = (sourceTask != null
+                        && (sourceTask.isVisible() || sourceTask == targetTask));
             }
         } else if (targetTask != null && (!taskToFront || avoidMoveTaskToFront)) {
             // We don't have a sourceRecord, and we're launching into an existing task.
             // Allow if callingUid is top of stack.
-            bas = isTopActivityMatchingUidAbsentForAsm(targetTask, callingUid,
-                    /*sourceRecord*/null);
+            bas = checkTopActivityForAsm(targetTask, callingUid,
+                    /*sourceRecord*/null, bas);
+        } else {
+            // We're launching from a non-visible activity. Has any visible app opted in?
+            TaskDisplayArea displayArea = targetTask != null && targetTask.getDisplayArea() != null
+                    ? targetTask.getDisplayArea()
+                    : preferredTaskDisplayArea;
+            if (displayArea != null) {
+                ArrayList<Task> visibleTasks = displayArea.getVisibleTasks();
+                for (int i = 0; i < visibleTasks.size(); i++) {
+                    Task task = visibleTasks.get(i);
+                    if (visibleTasks.size() == 1 && task.isActivityTypeHomeOrRecents()) {
+                        bas.optedIn(task.getTopMostActivity());
+                    } else {
+                        bas = checkTopActivityForAsm(task, callingUid, /*sourceRecord*/null, bas);
+                    }
+                }
+            }
         }
 
-        if (bas != null && !bas.mWouldBlockActivityStartIgnoringFlag) {
+        if (bas.mTopActivityMatchesSource) {
             return true;
         }
 
@@ -1140,13 +1123,16 @@
                 ? FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__ACTIVITY_START_SAME_TASK
                 : FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED__ACTION__ACTIVITY_START_DIFFERENT_TASK);
 
-        boolean blockActivityStartAndFeatureEnabled = ActivitySecurityModelFeatureFlags
-                .shouldRestrictActivitySwitch(callingUid)
-                && (bas == null || bas.mBlockActivityStartIfFlagEnabled);
+        boolean enforceBlock = bas.mTopActivityOptedIn
+                && ActivitySecurityModelFeatureFlags.shouldRestrictActivitySwitch(callingUid);
+
+        boolean allowedByGracePeriod = allowedByAsmGracePeriod(callingUid, sourceRecord, targetTask,
+                balCode, taskToFront, avoidMoveTaskToFront);
 
         String asmDebugInfo = getDebugInfoForActivitySecurity("Launch", sourceRecord,
                 targetRecord, targetTask, targetTopActivity, realCallingUid, balCode,
-                blockActivityStartAndFeatureEnabled, taskToFront, avoidMoveTaskToFront);
+                enforceBlock, taskToFront, avoidMoveTaskToFront, allowedByGracePeriod,
+                bas.mActivityOptedIn);
 
         FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_ACTION_BLOCKED,
                 /* caller_uid */
@@ -1184,7 +1170,7 @@
         String launchedFromPackageName = targetRecord.launchedFromPackage;
         if (ActivitySecurityModelFeatureFlags.shouldShowToast(callingUid)) {
             String toastText = ActivitySecurityModelFeatureFlags.DOC_LINK
-                    + (blockActivityStartAndFeatureEnabled ? " blocked " : " would block ")
+                    + (enforceBlock ? " blocked " : " would block ")
                     + getApplicationLabel(mService.mContext.getPackageManager(),
                     launchedFromPackageName);
             showToast(toastText);
@@ -1192,7 +1178,7 @@
             Slog.i(TAG, asmDebugInfo);
         }
 
-        if (blockActivityStartAndFeatureEnabled) {
+        if (enforceBlock) {
             Slog.e(TAG, "[ASM] Abort Launching r: " + targetRecord
                     + " as source: "
                     + (sourceRecord != null ? sourceRecord : launchedFromPackageName)
@@ -1251,18 +1237,18 @@
 
         // Find the first activity which matches a safe UID and is not finishing. Clear everything
         // above it
+        int[] finishCount = new int[1];
         boolean shouldBlockActivityStart = ActivitySecurityModelFeatureFlags
                 .shouldRestrictActivitySwitch(callingUid);
-        int[] finishCount = new int[0];
-        if (shouldBlockActivityStart
-                && blockCrossUidActivitySwitchFromBelowForActivity(targetTaskTop)) {
+        BlockActivityStart bas = checkCrossUidActivitySwitchFromBelow(
+                targetTaskTop, callingUid, new BlockActivityStart());
+        if (shouldBlockActivityStart && bas.mTopActivityOptedIn) {
             ActivityRecord activity = targetTask.getActivity(isLaunchingOrLaunched);
             if (activity == null) {
                 // mStartActivity is not in task, so clear everything
                 activity = targetRecord;
             }
 
-            finishCount = new int[1];
             targetTask.performClearTop(activity, launchFlags, finishCount);
             if (finishCount[0] > 0) {
                 Slog.w(TAG, "Cleared top n: " + finishCount[0] + " activities from task t: "
@@ -1279,7 +1265,8 @@
 
             Slog.i(TAG, getDebugInfoForActivitySecurity("Clear Top", sourceRecord, targetRecord,
                     targetTask, targetTaskTop, realCallingUid, balCode, shouldBlockActivityStart,
-                    /* taskToFront */ true, /* avoidMoveTaskToFront */ false));
+                    /* taskToFront */ true, /* avoidMoveTaskToFront */ false,
+                    /* allowedByAsmGracePeriod */ false, bas.mActivityOptedIn));
         }
     }
 
@@ -1287,7 +1274,7 @@
      * Returns home if the passed in callingUid is not top of the stack, rather than returning to
      * previous task.
      */
-    void checkActivityAllowedToClearTask(@NonNull Task task, int callingUid,
+    void checkActivityAllowedToClearTask(@NonNull Task task, int callingUid, int callingPid,
             @NonNull String callerActivityClassName) {
         // We may have already checked that the callingUid has additional clearTask privileges, and
         // cleared the calling identify. If so, we infer we do not need further restrictions here.
@@ -1295,14 +1282,28 @@
             return;
         }
 
+        String packageName =  mService.mContext.getPackageManager().getNameForUid(callingUid);
+        BalState state = new BalState(callingUid, callingPid, packageName, INVALID_UID,
+                INVALID_PID, null, null, null, null, null, ActivityOptions.makeBasic());
+        @BalCode int balCode = checkBackgroundActivityStartAllowedByCaller(state).mCode;
+        if (balCode == BAL_ALLOW_ALLOWLISTED_UID
+                || balCode == BAL_ALLOW_ALLOWLISTED_COMPONENT
+                || balCode == BAL_ALLOW_PERMISSION
+                || balCode == BAL_ALLOW_SAW_PERMISSION
+                || balCode == BAL_ALLOW_VISIBLE_WINDOW
+                || balCode == BAL_ALLOW_NON_APP_VISIBLE_WINDOW) {
+            return;
+        }
+
         TaskDisplayArea displayArea = task.getTaskDisplayArea();
         if (displayArea == null) {
             // If there is no associated display area, we can not return home.
             return;
         }
 
-        BlockActivityStart bas = isTopActivityMatchingUidAbsentForAsm(task, callingUid, null);
-        if (!bas.mWouldBlockActivityStartIgnoringFlag) {
+        BlockActivityStart bas = checkTopActivityForAsm(task, callingUid, null,
+                new BlockActivityStart());
+        if (bas.mTopActivityMatchesSource) {
             return;
         }
 
@@ -1339,8 +1340,7 @@
         );
 
         boolean restrictActivitySwitch = ActivitySecurityModelFeatureFlags
-                .shouldRestrictActivitySwitch(callingUid)
-                        && bas.mBlockActivityStartIfFlagEnabled;
+                .shouldRestrictActivitySwitch(callingUid) && bas.mTopActivityOptedIn;
 
         PackageManager pm = mService.mContext.getPackageManager();
         String callingPackage = pm.getNameForUid(callingUid);
@@ -1381,32 +1381,30 @@
      * <p>
      * The 'sourceRecord' can be considered top even if it is 'finishing'
      * <p>
-     * Returns a class where the elements are:
-     * <pre>
-     * shouldBlockActivityStart: {@code true} if we should actually block the transition (takes into
-     * consideration feature flag and targetSdk).
-     * wouldBlockActivityStartIgnoringFlags: {@code true} if we should warn about the transition via
-     * toasts. This happens if the transition would be blocked in case both the app was targeting V+
-     * and the feature was enabled.
-     * </pre>
      */
-    private BlockActivityStart isTopActivityMatchingUidAbsentForAsm(@NonNull Task task,
-            int uid, @Nullable ActivityRecord sourceRecord) {
+    private BlockActivityStart checkTopActivityForAsm(@NonNull Task task,
+            int uid, @Nullable ActivityRecord sourceRecord, BlockActivityStart bas) {
         // If the source is visible, consider it 'top'.
         if (sourceRecord != null && sourceRecord.isVisibleRequested()) {
-            return BlockActivityStart.ACTIVITY_START_ALLOWED;
+            return bas.matchesSource();
         }
 
-        // Always allow actual top activity to clear task
+        // Always allow actual top activity
         ActivityRecord topActivity = task.getTopMostActivity();
-        if (topActivity != null && topActivity.isUid(uid)) {
-            return BlockActivityStart.ACTIVITY_START_ALLOWED;
+        if (topActivity == null) {
+            Slog.wtf(TAG, "Activities for task: " + task + " not found.");
+            return bas.optedIn(topActivity);
+        }
+
+        bas = checkCrossUidActivitySwitchFromBelow(topActivity, uid, bas);
+        if (bas.mTopActivityMatchesSource) {
+            return bas;
         }
 
         // If UID is visible in target task, allow launch
         if (task.forAllActivities((Predicate<ActivityRecord>)
                 ar -> ar.isUid(uid) && ar.isVisibleRequested())) {
-            return BlockActivityStart.ACTIVITY_START_ALLOWED;
+            return bas.matchesSource();
         }
 
         // Consider the source activity, whether or not it is finishing. Do not consider any other
@@ -1417,82 +1415,91 @@
         // Check top of stack (or the first task fragment for embedding).
         topActivity = task.getActivity(topOfStackPredicate);
         if (topActivity == null) {
-            return new BlockActivityStart(true, true);
+            return bas;
         }
 
-        BlockActivityStart pair = blockCrossUidActivitySwitchFromBelow(topActivity, uid);
-        if (!pair.mBlockActivityStartIfFlagEnabled) {
-            return pair;
+        bas = checkCrossUidActivitySwitchFromBelow(topActivity, uid, bas);
+        if (bas.mTopActivityMatchesSource) {
+            return bas;
         }
 
         // Even if the top activity is not a match, we may be in an embedded activity scenario with
         // an adjacent task fragment. Get the second fragment.
         TaskFragment taskFragment = topActivity.getTaskFragment();
         if (taskFragment == null) {
-            return pair;
+            return bas;
         }
 
         TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
         if (adjacentTaskFragment == null) {
-            return pair;
+            return bas;
         }
 
         // Check the second fragment.
         topActivity = adjacentTaskFragment.getActivity(topOfStackPredicate);
         if (topActivity == null) {
-            return new BlockActivityStart(true, true);
+            return bas;
         }
 
-        return blockCrossUidActivitySwitchFromBelow(topActivity, uid);
+        return checkCrossUidActivitySwitchFromBelow(topActivity, uid, bas);
     }
 
     /**
      * Determines if a source is allowed to add or remove activities from the task,
      * if the current ActivityRecord is above it in the stack
      * <p>
-     * A transition is blocked ({@code false} returned) if all of the following are met:
+     * A transition is blocked if all of the following are met:
      * <pre>
      * 1. The source activity and the current activity record belong to different apps
      * (i.e, have different UIDs).
-     * 2. Both the source activity and the current activity target U+
-     * 3. The current activity has not set
+     * 2. The current activity target V+
+     * 3. The current app has set
+     * {@link R.styleable#AndroidManifestApplication_allowCrossUidActivitySwitchFromBelow}
+     * to {@code false}
+     * 4. The current activity has not set
      * {@link ActivityRecord#setAllowCrossUidActivitySwitchFromBelow(boolean)} to {@code true}
      * </pre>
      *
-     * Returns a class where the elements are:
-     * <pre>
-     * shouldBlockActivityStart: {@code true} if we should actually block the transition (takes into
-     * consideration feature flag and targetSdk).
-     * wouldBlockActivityStartIgnoringFlags: {@code true} if we should warn about the transition via
-     * toasts. This happens if the transition would be blocked in case both the app was targeting V+
-     * and the feature was enabled.
-     * </pre>
      *
      * @param sourceUid The source (s) activity performing the state change
      */
-    private BlockActivityStart blockCrossUidActivitySwitchFromBelow(ActivityRecord ar,
-            int sourceUid) {
+    private BlockActivityStart checkCrossUidActivitySwitchFromBelow(ActivityRecord ar,
+            int sourceUid, BlockActivityStart bas) {
         if (ar.isUid(sourceUid)) {
-            return BlockActivityStart.ACTIVITY_START_ALLOWED;
+            return bas.matchesSource();
         }
 
-        if (!blockCrossUidActivitySwitchFromBelowForActivity(ar)) {
-            return BlockActivityStart.ACTIVITY_START_ALLOWED;
+        // We don't need to check package level if activity has opted out.
+        if (ar.mAllowCrossUidActivitySwitchFromBelow) {
+            bas.mTopActivityOptedIn = false;
+            return bas.matchesSource();
         }
 
-        // At this point, we would block if the feature is launched and both apps were V+
-        // Since we have a feature flag, we need to check that too
-        // TODO(b/258792202) Replace with CompatChanges and replace Pair with boolean once feature
-        // flag is removed
-        boolean restrictActivitySwitch =
-                ActivitySecurityModelFeatureFlags.shouldRestrictActivitySwitch(ar.getUid())
-                        && ActivitySecurityModelFeatureFlags
-                        .shouldRestrictActivitySwitch(sourceUid);
-        if (restrictActivitySwitch) {
-            return BlockActivityStart.BLOCK;
-        } else {
-            return BlockActivityStart.LOG_ONLY;
+        if (!CompatChanges.isChangeEnabled(ASM_RESTRICTIONS, ar.getUid())) {
+            return bas;
         }
+
+        if (ar.isUid(SYSTEM_UID)) {
+            return bas.optedIn(ar);
+        }
+
+        String packageName = ar.packageName;
+        if (packageName == null) {
+            Slog.wtf(TAG, "Package name: " + ar + " not found.");
+            return bas.optedIn(ar);
+        }
+
+        PackageManager pm = mService.mContext.getPackageManager();
+        ApplicationInfo applicationInfo;
+
+        try {
+            applicationInfo = pm.getApplicationInfo(packageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.wtf(TAG, "Package name: " + packageName + " not found.");
+            return bas.optedIn(ar);
+        }
+
+        return applicationInfo.allowCrossUidActivitySwitchFromBelow ? bas : bas.optedIn(ar);
     }
 
     /**
@@ -1502,8 +1509,9 @@
             @Nullable ActivityRecord sourceRecord, @NonNull ActivityRecord targetRecord,
             @Nullable Task targetTask, @Nullable ActivityRecord targetTopActivity,
             int realCallingUid, @BalCode int balCode,
-            boolean blockActivityStartAndFeatureEnabled, boolean taskToFront,
-            boolean avoidMoveTaskToFront) {
+            boolean enforceBlock, boolean taskToFront,
+            boolean avoidMoveTaskToFront, boolean allowedByGracePeriod,
+            ActivityRecord activityOptedIn) {
         final String prefix = "[ASM] ";
         Function<ActivityRecord, String> recordToString = (ar) -> {
             if (ar == null) {
@@ -1519,9 +1527,16 @@
 
         StringJoiner joiner = new StringJoiner("\n");
         joiner.add(prefix + "------ Activity Security " + action + " Debug Logging Start ------");
-        joiner.add(prefix + "Block Enabled: " + blockActivityStartAndFeatureEnabled);
+        joiner.add(prefix + "Block Enabled: " + enforceBlock);
+        if (!enforceBlock) {
+            joiner.add(prefix + "Feature Flag Enabled: " + android.security
+                    .Flags.asmRestrictionsEnabled());
+            joiner.add(prefix + "Mendel Override: " + ActivitySecurityModelFeatureFlags
+                    .asmRestrictionsEnabledForAll());
+        }
         joiner.add(prefix + "ASM Version: " + ActivitySecurityModelFeatureFlags.ASM_VERSION);
         joiner.add(prefix + "System Time: " + SystemClock.uptimeMillis());
+        joiner.add(prefix + "Activity Opted In: " + recordToString.apply(activityOptedIn));
 
         boolean targetTaskMatchesSourceTask = targetTask != null
                 && sourceRecord != null && sourceRecord.getTask() == targetTask;
@@ -1561,6 +1576,7 @@
         joiner.add(prefix + "TaskToFront: " + taskToFront);
         joiner.add(prefix + "AvoidMoveToFront: " + avoidMoveTaskToFront);
         joiner.add(prefix + "BalCode: " + balCodeToString(balCode));
+        joiner.add(prefix + "Allowed By Grace Period: " + allowedByGracePeriod);
         joiner.add(prefix + "LastResumedActivity: "
                        + recordToString.apply(mService.mLastResumedActivity));
 
@@ -1588,6 +1604,44 @@
         return joiner.toString();
     }
 
+    private boolean allowedByAsmGracePeriod(int callingUid, @Nullable ActivityRecord sourceRecord,
+            @Nullable Task targetTask, @BalCode int balCode, boolean taskToFront,
+            boolean avoidMoveTaskToFront) {
+        if (balCode == BAL_ALLOW_GRACE_PERIOD) {
+            // Allow if launching into new task, and caller matches most recently finished activity
+            if (taskToFront && mTopFinishedActivity != null
+                    && mTopFinishedActivity.mUid == callingUid) {
+                return true;
+            }
+
+            // Launching into existing task - allow if matches most recently finished activity
+            // within the task.
+            // We can reach here multiple ways:
+            // 1. activity in fg fires intent (taskToFront = false, sourceRecord is available)
+            // 2. activity in bg fires intent (taskToFront = false, sourceRecord is available)
+            // 3. activity in bg fires intent with NEW_FLAG (taskToFront = true,
+            //         avoidMoveTaskToFront = true, sourceRecord is available)
+            // 4. activity in bg fires PI (taskToFront = true, avoidMoveTaskToFront = true,
+            //         sourceRecord is not available, targetTask may be available)
+            if (!taskToFront || avoidMoveTaskToFront) {
+                if (targetTask != null) {
+                    FinishedActivityEntry finishedEntry =
+                            mTaskIdToFinishedActivity.get(targetTask.mTaskId);
+                    if (finishedEntry != null && finishedEntry.mUid == callingUid) {
+                        return true;
+                    }
+                }
+
+                if (sourceRecord != null) {
+                    FinishedActivityEntry finishedEntry =
+                            mTaskIdToFinishedActivity.get(sourceRecord.getTask().mTaskId);
+                    return finishedEntry != null && finishedEntry.mUid == callingUid;
+                }
+            }
+        }
+        return false;
+    }
+
     private static boolean isSystemExemptFlagEnabled() {
         return DeviceConfig.getBoolean(
                 NAMESPACE_WINDOW_MANAGER,
@@ -1698,55 +1752,22 @@
         }
     }
 
-    /**
-     * Activity level allowCrossUidActivitySwitchFromBelow defaults to false.
-     * Package level defaults to true.
-     * We block the launch if dev has explicitly set package level to false, and activity level has
-     * not opted out
-     */
-    private boolean blockCrossUidActivitySwitchFromBelowForActivity(@NonNull ActivityRecord ar) {
-        // We don't need to check package level if activity has opted out.
-        if (ar.mAllowCrossUidActivitySwitchFromBelow) {
-            return false;
-        }
-
-        if (ActivitySecurityModelFeatureFlags.asmRestrictionsEnabledForAll()) {
-            return true;
-        }
-
-        String packageName = ar.packageName;
-        if (packageName == null) {
-            return false;
-        }
-
-        PackageManager pm = mService.mContext.getPackageManager();
-        ApplicationInfo applicationInfo;
-
-        try {
-            applicationInfo = pm.getApplicationInfo(packageName, 0);
-        } catch (PackageManager.NameNotFoundException e) {
-            Slog.wtf(TAG, "Package name: " + packageName + " not found.");
-            return false;
-        }
-
-        return !applicationInfo.allowCrossUidActivitySwitchFromBelow;
-    }
-
     private static class BlockActivityStart {
-        private static final BlockActivityStart ACTIVITY_START_ALLOWED =
-                new BlockActivityStart(false, false);
-        private static final BlockActivityStart LOG_ONLY = new BlockActivityStart(false, true);
-        private static final BlockActivityStart BLOCK = new BlockActivityStart(true, true);
-        // We should block if feature flag is enabled
-        private final boolean mBlockActivityStartIfFlagEnabled;
-        // Used for logging/toasts. Would we block if target sdk was V and feature was
-        // enabled?
-        private final boolean mWouldBlockActivityStartIgnoringFlag;
+        private boolean mTopActivityOptedIn;
+        private boolean mTopActivityMatchesSource;
+        private ActivityRecord mActivityOptedIn;
 
-        private BlockActivityStart(boolean shouldBlockActivityStart,
-                boolean wouldBlockActivityStartIgnoringFlags) {
-            this.mBlockActivityStartIfFlagEnabled = shouldBlockActivityStart;
-            this.mWouldBlockActivityStartIgnoringFlag = wouldBlockActivityStartIgnoringFlags;
+        BlockActivityStart optedIn(ActivityRecord activity) {
+            mTopActivityOptedIn = true;
+            if (mActivityOptedIn == null) {
+                mActivityOptedIn = activity;
+            }
+            return this;
+        }
+
+        BlockActivityStart matchesSource() {
+            mTopActivityMatchesSource = true;
+            return this;
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ClientLifecycleManager.java b/services/core/java/com/android/server/wm/ClientLifecycleManager.java
index e48e4e8..816fe1d 100644
--- a/services/core/java/com/android/server/wm/ClientLifecycleManager.java
+++ b/services/core/java/com/android/server/wm/ClientLifecycleManager.java
@@ -22,6 +22,7 @@
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.ClientTransactionItem;
 import android.os.Binder;
+import android.os.Build;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.Trace;
@@ -179,6 +180,22 @@
         Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
     }
 
+    /** Executes the pending transaction for the given client process. */
+    void dispatchPendingTransaction(@NonNull IApplicationThread client) {
+        if (!Flags.bundleClientTransactionFlag()) {
+            return;
+        }
+        final ClientTransaction pendingTransaction = mPendingTransactions.remove(client.asBinder());
+        if (pendingTransaction != null) {
+            try {
+                scheduleTransaction(pendingTransaction);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to deliver pending transaction", e);
+                // TODO(b/323801078): apply cleanup for individual transaction item if needed.
+            }
+        }
+    }
+
     /**
      * Called to when {@link WindowSurfacePlacer#continueLayout}.
      * Dispatches all pending transactions unless there is an ongoing/scheduled layout, in which
@@ -233,4 +250,17 @@
                 && !mWms.mWindowPlacerLocked.isTraversalScheduled()
                 && !mWms.mWindowPlacerLocked.isInLayout();
     }
+
+    /**
+     * Guards the bundleClientTransactionFlag feature with targetSDK on Android 15+.
+     *
+     * Suppressing because it can't guard with @EnabledSince on VANILLA_ICE_CREAM yet since the
+     * version is not published.
+     *
+     * TODO(b/324203798): update in V
+     */
+    @SuppressWarnings("AndroidFrameworkCompatChange")
+    static boolean shouldDispatchCompatClientTransactionIndependently(int appTargetSdk) {
+        return appTargetSdk <= Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 8717098..a914c07 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -650,6 +650,14 @@
         if (isCurrentlyRecording() && mLastRecordedBounds != null) {
             mMediaProjectionManager.notifyActiveProjectionCapturedContentVisibilityChanged(
                     isVisibleRequested);
+
+            if (mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK) {
+                // If capturing a task, then the toggle visibility of the recorded surface to match
+                // visibility of the task, so we don't capture any mid-transition frames
+                mRecordedWindowContainer.getSyncTransaction()
+                        .setVisibility(mRecordedSurface, isVisibleRequested);
+                mRecordedWindowContainer.scheduleAnimation();
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
index 1dc9493..925a077 100644
--- a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
@@ -16,8 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.util.DisplayMetrics.DENSITY_DEFAULT;
-
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
@@ -29,8 +27,7 @@
 import android.util.Slog;
 
 import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
-import com.android.wm.shell.Flags;
-
+import com.android.window.flags.Flags;
 /**
  * The class that defines default launch params for tasks in desktop mode
  */
@@ -40,16 +37,11 @@
             TAG_WITH_CLASS_NAME ? "DesktopModeLaunchParamsModifier" : TAG_ATM;
     private static final boolean DEBUG = false;
 
-    // Desktop mode feature flags.
-    private static final boolean ENABLE_DESKTOP_WINDOWING = Flags.enableDesktopWindowing();
     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.
-    private static final int DESKTOP_MODE_DEFAULT_WIDTH_DP = SystemProperties.getInt(
-            "persist.wm.debug.desktop_mode.default_width", 840);
-    // Override default freeform task height when desktop mode is enabled. In dips.
-    private static final int DESKTOP_MODE_DEFAULT_HEIGHT_DP = SystemProperties.getInt(
-            "persist.wm.debug.desktop_mode.default_height", 630);
+    public static final float DESKTOP_MODE_INITIAL_BOUNDS_SCALE =
+            SystemProperties
+                    .getInt("persist.wm.debug.desktop_mode_initial_bounds_scale", 75) / 100f;
 
     private StringBuilder mLogBuilder;
 
@@ -73,6 +65,11 @@
             LaunchParamsController.LaunchParams currentParams,
             LaunchParamsController.LaunchParams outParams) {
 
+        if (!isDesktopModeEnabled()) {
+            appendLog("desktop mode is not enabled, continuing");
+            return RESULT_CONTINUE;
+        }
+
         if (task == null) {
             appendLog("task null, skipping");
             return RESULT_SKIP;
@@ -93,7 +90,7 @@
         // previous windowing mode to be restored even if the desktop mode state has changed.
         // Let task launches inherit the windowing mode from the source task if available, which
         // should have the desired windowing mode set by WM Shell. See b/286929122.
-        if (isDesktopModeSupported() && source != null && source.getTask() != null) {
+        if (isDesktopModeEnabled() && source != null && source.getTask() != null) {
             final Task sourceTask = source.getTask();
             outParams.mWindowingMode = sourceTask.getWindowingMode();
             appendLog("inherit-from-source=" + outParams.mWindowingMode);
@@ -108,23 +105,29 @@
             return RESULT_SKIP;
         }
 
-        // Update width and height with default desktop mode values
-        float density = (float) task.getConfiguration().densityDpi / DENSITY_DEFAULT;
-        final int width = (int) (DESKTOP_MODE_DEFAULT_WIDTH_DP * density + 0.5f);
-        final int height = (int) (DESKTOP_MODE_DEFAULT_HEIGHT_DP * density + 0.5f);
-        outParams.mBounds.right = width;
-        outParams.mBounds.bottom = height;
-
-        // Center the task in window bounds
-        Rect windowBounds = task.getWindowConfiguration().getBounds();
-        outParams.mBounds.offset(windowBounds.centerX() - outParams.mBounds.centerX(),
-                windowBounds.centerY() - outParams.mBounds.centerY());
+        calculateAndCentreInitialBounds(task, outParams);
 
         appendLog("setting desktop mode task bounds to %s", outParams.mBounds);
 
         return RESULT_DONE;
     }
 
+    /**
+     * Calculates the initial height and width of a task in desktop mode and centers it within the
+     * window bounds.
+     */
+    private void calculateAndCentreInitialBounds(Task task,
+            LaunchParamsController.LaunchParams outParams) {
+        // TODO(b/319819547): Account for app constraints so apps do not become letterboxed
+        final Rect windowBounds = task.getDisplayArea().getBounds();
+        final int width = (int) (windowBounds.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+        final int height = (int) (windowBounds.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+        outParams.mBounds.right = width;
+        outParams.mBounds.bottom = height;
+        outParams.mBounds.offset(windowBounds.centerX() - outParams.mBounds.centerX(),
+                windowBounds.centerY() - outParams.mBounds.centerY());
+    }
+
     private void initLogBuilder(Task task, ActivityRecord activity) {
         if (DEBUG) {
             mLogBuilder = new StringBuilder(
@@ -140,14 +143,8 @@
         if (DEBUG) Slog.d(TAG, mLogBuilder.toString());
     }
 
-    /** Whether desktop mode is supported. */
-    static boolean isDesktopModeSupported() {
-        // Check for aconfig flag first
-        if (ENABLE_DESKTOP_WINDOWING) {
-            return true;
-        }
-        // Fall back to sysprop flag
-        // TODO(b/304778354): remove sysprop once desktop aconfig flag supports dynamic overriding
-        return DESKTOP_MODE_PROTO2_SUPPORTED;
+    /** Whether desktop mode is enabled. */
+    static boolean isDesktopModeEnabled() {
+        return Flags.enableDesktopWindowingMode();
     }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 5cf9acd..7f3df95 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -47,6 +47,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_UNRESTRICTED_GESTURE_EXCLUSION;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
@@ -1533,9 +1534,19 @@
         // Check the windows that overlap with system bars to determine system bars' appearance.
         if ((appWindow && attached == null && attrs.isFullscreen())
                 || attrs.type == TYPE_VOICE_INTERACTION) {
-            // Record the top-fullscreen-app-window which will be used to determine system UI
+
+            // If this is the exiting starting window, don't let it control the system bars.
+            // The app window behind it should be the controlling window instead. Reason: when an
+            // activity starts another activity behind a starting window, the app window of the
+            // first activity will lose the window focus. And then mTopFullscreenOpaqueWindowState
+            // will control the system bars. The logic here is to let first app window keep
+            // controlling system bars until the second app window is ready.
+            final boolean exitingStartingWindow =
+                    attrs.type == TYPE_APPLICATION_STARTING && win.mAnimatingExit;
+
+            // Record the top-fullscreen-app-window which will be used to determine the system UI
             // controlling window.
-            if (mTopFullscreenOpaqueWindowState == null) {
+            if (mTopFullscreenOpaqueWindowState == null && !exitingStartingWindow) {
                 mTopFullscreenOpaqueWindowState = win;
             }
 
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index b68e67e..34ea4ac 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -18,6 +18,7 @@
 
 import static android.view.View.DRAG_FLAG_GLOBAL;
 import static android.view.View.DRAG_FLAG_GLOBAL_SAME_APPLICATION;
+import static android.view.View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG;
 
 import static com.android.input.flags.Flags.enablePointerChoreographer;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
@@ -373,8 +374,11 @@
     boolean notifyUnhandledDrop(DragEvent dropEvent, String reason) {
         final boolean isLocalDrag =
                 (mDragState.mFlags & (DRAG_FLAG_GLOBAL_SAME_APPLICATION | DRAG_FLAG_GLOBAL)) == 0;
+        final boolean shouldDelegateUnhandledDrag =
+                (mDragState.mFlags & DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG) != 0;
         if (!com.android.window.flags.Flags.delegateUnhandledDrags()
                 || mGlobalDragListener == null
+                || !shouldDelegateUnhandledDrag
                 || isLocalDrag) {
             // Skip if the flag is disabled, there is no unhandled-drag listener, or if this is a
             // purely local drag
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 76038b9..b266caa 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -216,8 +216,7 @@
         mIsClosing = true;
         // Unregister the input interceptor.
         if (mInputInterceptor != null) {
-            if (DEBUG_DRAG)
-                Slog.d(TAG_WM, "unregistering drag input channel");
+            if (DEBUG_DRAG) Slog.d(TAG_WM, "Unregistering drag input channel");
 
             // Input channel should be disposed on the thread where the input is being handled.
             mDragDropController.sendHandlerMessage(
@@ -227,9 +226,7 @@
 
         // Send drag end broadcast if drag start has been sent.
         if (mDragInProgress) {
-            if (DEBUG_DRAG) {
-                Slog.d(TAG_WM, "broadcasting DRAG_ENDED");
-            }
+            if (DEBUG_DRAG) Slog.d(TAG_WM, "Broadcasting DRAG_ENDED");
             for (WindowState ws : mNotifiedWindows) {
                 float x = 0;
                 float y = 0;
@@ -248,6 +245,7 @@
                         x, y, mThumbOffsetX, mThumbOffsetY, null, null, null, dragSurface, null,
                         mDragResult);
                 try {
+                    if (DEBUG_DRAG) Slog.d(TAG_WM, "Sending DRAG_ENDED to " + ws);
                     ws.mClient.dispatchDragEvent(event);
                 } catch (RemoteException e) {
                     Slog.w(TAG_WM, "Unable to drag-end window " + ws);
@@ -364,7 +362,7 @@
             return false;
         }
 
-        if (DEBUG_DRAG) Slog.d(TAG_WM, "sending DROP to " + touchedWin);
+        if (DEBUG_DRAG) Slog.d(TAG_WM, "Sending DROP to " + touchedWin);
 
         final IBinder clientToken = touchedWin.mClient.asBinder();
         final DragEvent event = createDropEvent(x, y, touchedWin, false /* includePrivateInfo */);
@@ -460,7 +458,7 @@
      */
     CompletableFuture<Void> register(Display display) {
         display.getRealSize(mDisplaySize);
-        if (DEBUG_DRAG) Slog.d(TAG_WM, "registering drag input channel");
+        if (DEBUG_DRAG) Slog.d(TAG_WM, "Registering drag input channel");
         if (mInputInterceptor != null) {
             Slog.e(TAG_WM, "Duplicate register of drag input channel");
             return completedFuture(null);
@@ -489,7 +487,7 @@
                 mSourceUserId, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
 
         if (DEBUG_DRAG) {
-            Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")");
+            Slog.d(TAG_WM, "Broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")");
         }
 
         final boolean containsAppExtras = containsApplicationExtras(mDataDescription);
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index ea31e63..9fee343 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -215,11 +215,11 @@
      * when {@link android.inputmethodservice.InputMethodService} requests to show IME
      * on {@param imeTarget}.
      *
-     * @param imeTarget imeTarget on which IME show request is coming from.
-     * @param statsToken the token tracking the current IME show request or {@code null} otherwise.
+     * @param imeTarget imeTarget on which IME request is coming from.
+     * @param statsToken the token tracking the current IME request.
      */
     void scheduleShowImePostLayout(InsetsControlTarget imeTarget,
-            @Nullable ImeTracker.Token statsToken) {
+            @NonNull ImeTracker.Token statsToken) {
         boolean targetChanged = isTargetChangedWithinActivity(imeTarget);
         mImeRequester = imeTarget;
         // Cancel the pre-existing stats token, if any.
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
index b74eb56..cc3de7a 100644
--- a/services/core/java/com/android/server/wm/InsetsControlTarget.java
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -60,8 +60,8 @@
      * Instructs the control target to show inset sources.
      *
      * @param types to specify which types of insets source window should be shown.
-     * @param fromIme {@code true} if IME show request originated from {@link InputMethodService}.
-     * @param statsToken the token tracking the current IME show request or {@code null} otherwise.
+     * @param fromIme {@code true} if the IME request originated from {@link InputMethodService}.
+     * @param statsToken the token tracking the current IME request or {@code null} otherwise.
      */
     default void showInsets(@InsetsType int types, boolean fromIme,
             @Nullable ImeTracker.Token statsToken) {
@@ -71,8 +71,8 @@
      * Instructs the control target to hide inset sources.
      *
      * @param types to specify which types of insets source window should be hidden.
-     * @param fromIme {@code true} if IME hide request originated from {@link InputMethodService}.
-     * @param statsToken the token tracking the current IME hide request or {@code null} otherwise.
+     * @param fromIme {@code true} if the IME request originated from {@link InputMethodService}.
+     * @param statsToken the token tracking the current IME request or {@code null} otherwise.
      */
     default void hideInsets(@InsetsType int types, boolean fromIme,
             @Nullable ImeTracker.Token statsToken) {
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index cd96806..fa76774 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -520,11 +520,37 @@
         updateVisibility();
         mControl = new InsetsSourceControl(mSource.getId(), mSource.getType(), leash,
                 mClientVisible, surfacePosition, getInsetsHint());
+        mStateController.notifySurfaceTransactionReady(this, getSurfaceTransactionId(leash), true);
 
         ProtoLog.d(WM_DEBUG_WINDOW_INSETS,
                 "InsetsSource Control %s for target %s", mControl, mControlTarget);
     }
 
+    private long getSurfaceTransactionId(SurfaceControl leash) {
+        // Here returns mNativeObject (long) as the ID instead of the leash itself so that
+        // InsetsStateController won't keep referencing the leash unexpectedly.
+        return leash != null ? leash.mNativeObject : 0;
+    }
+
+    /**
+     * This is called when the surface transaction of the leash initialization has been committed.
+     *
+     * @param id Indicates which transaction is committed so that stale callbacks can be dropped.
+     */
+    void onSurfaceTransactionCommitted(long id) {
+        if (mIsLeashReadyForDispatching) {
+            return;
+        }
+        if (mControl == null) {
+            return;
+        }
+        if (id != getSurfaceTransactionId(mControl.getLeash())) {
+            return;
+        }
+        mIsLeashReadyForDispatching = true;
+        mStateController.notifySurfaceTransactionReady(this, 0, false);
+    }
+
     void startSeamlessRotation() {
         if (!mSeamlessRotating) {
             mSeamlessRotating = true;
@@ -545,10 +571,6 @@
         return true;
     }
 
-    void onSurfaceTransactionApplied() {
-        mIsLeashReadyForDispatching = true;
-    }
-
     void setClientVisible(boolean clientVisible) {
         if (mClientVisible == clientVisible) {
             return;
@@ -733,6 +755,7 @@
         public void onAnimationCancelled(SurfaceControl animationLeash) {
             if (mAdapter == this) {
                 mStateController.notifyControlRevoked(mControlTarget, InsetsSourceProvider.this);
+                mStateController.notifySurfaceTransactionReady(InsetsSourceProvider.this, 0, false);
                 mControl = null;
                 mControlTarget = null;
                 mAdapter = null;
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 6b9fcf4..ba578f6 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -34,6 +34,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.SparseArray;
+import android.util.SparseLongArray;
 import android.util.proto.ProtoOutputStream;
 import android.view.InsetsSource;
 import android.view.InsetsSourceControl;
@@ -58,6 +59,7 @@
     private final DisplayContent mDisplayContent;
 
     private final SparseArray<InsetsSourceProvider> mProviders = new SparseArray<>();
+    private final SparseLongArray mSurfaceTransactionIds = new SparseLongArray();
     private final ArrayMap<InsetsControlTarget, ArrayList<InsetsSourceProvider>>
             mControlTargetProvidersMap = new ArrayMap<>();
     private final SparseArray<InsetsControlTarget> mIdControlTargetMap = new SparseArray<>();
@@ -360,14 +362,32 @@
         notifyPendingInsetsControlChanged();
     }
 
+    void notifySurfaceTransactionReady(InsetsSourceProvider provider, long id, boolean ready) {
+        if (ready) {
+            mSurfaceTransactionIds.put(provider.getSource().getId(), id);
+        } else {
+            mSurfaceTransactionIds.delete(provider.getSource().getId());
+        }
+    }
+
     private void notifyPendingInsetsControlChanged() {
         if (mPendingControlChanged.isEmpty()) {
             return;
         }
+        final int size = mSurfaceTransactionIds.size();
+        final SparseLongArray surfaceTransactionIds = new SparseLongArray(size);
+        for (int i = 0; i < size; i++) {
+            surfaceTransactionIds.append(
+                    mSurfaceTransactionIds.keyAt(i), mSurfaceTransactionIds.valueAt(i));
+        }
         mDisplayContent.mWmService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
-            for (int i = mProviders.size() - 1; i >= 0; i--) {
-                final InsetsSourceProvider provider = mProviders.valueAt(i);
-                provider.onSurfaceTransactionApplied();
+            for (int i = 0; i < size; i++) {
+                final int sourceId = surfaceTransactionIds.keyAt(i);
+                final InsetsSourceProvider provider = mProviders.get(sourceId);
+                if (provider == null) {
+                    continue;
+                }
+                provider.onSurfaceTransactionCommitted(surfaceTransactionIds.valueAt(i));
             }
             final ArraySet<InsetsControlTarget> newControlTargets = new ArraySet<>();
             int displayId = mDisplayContent.getDisplayId();
diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java
index 91bb8d0..97b5925 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsController.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsController.java
@@ -64,10 +64,7 @@
     void registerDefaultModifiers(ActivityTaskSupervisor supervisor) {
         // {@link TaskLaunchParamsModifier} handles window layout preferences.
         registerModifier(new TaskLaunchParamsModifier(supervisor));
-        if (DesktopModeLaunchParamsModifier.isDesktopModeSupported()) {
-            // {@link DesktopModeLaunchParamsModifier} handles default task size changes
-            registerModifier(new DesktopModeLaunchParamsModifier());
-        }
+        registerModifier(new DesktopModeLaunchParamsModifier());
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS
index e06f215..79eb0dc 100644
--- a/services/core/java/com/android/server/wm/OWNERS
+++ b/services/core/java/com/android/server/wm/OWNERS
@@ -24,3 +24,5 @@
 per-file Background*Start* = file:/BAL_OWNERS
 per-file Background*Start* = ogunwale@google.com, louischang@google.com
 
+# File related to activity callers
+per-file ActivityCallerState.java = file:/core/java/android/app/COMPONENT_CALLER_OWNERS
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index e027eb6..dd14642 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.app.ActivityManager.FLAG_AND_UNLOCKED;
 import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
 import static android.app.ActivityManager.RECENT_WITH_EXCLUDED;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
@@ -69,6 +68,7 @@
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.ArraySet;
+import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -89,9 +89,9 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Class for managing the recent tasks list. The list is ordered by most recent (index 0) to the
@@ -167,8 +167,9 @@
 
     /**
      * Mapping of user id -> whether recent tasks have been loaded for that user.
+     * The AtomicBoolean per user will be locked when reading persisted task from storage.
      */
-    private final SparseBooleanArray mUsersWithRecentsLoaded = new SparseBooleanArray(
+    private final SparseArray<AtomicBoolean> mUsersWithRecentsLoaded = new SparseArray<>(
             DEFAULT_INITIAL_CAPACITY);
 
     /**
@@ -481,29 +482,49 @@
 
     /**
      * Loads the persistent recentTasks for {@code userId} into this list from persistent storage.
-     * Does nothing if they are already loaded.
-     *
-     * @param userId the user Id
+     * Does nothing if they are already loaded. This may perform IO operation, so the caller should
+     * not hold a lock.
      */
-    void loadUserRecentsLocked(int userId) {
-        if (mUsersWithRecentsLoaded.get(userId)) {
-            // User already loaded, return early
-            return;
-        }
-
-        // Load the task ids if not loaded.
-        loadPersistedTaskIdsForUserLocked(userId);
-
-        // Check if any tasks are added before recents is loaded
-        final SparseBooleanArray preaddedTasks = new SparseBooleanArray();
-        for (final Task task : mTasks) {
-            if (task.mUserId == userId && shouldPersistTaskLocked(task)) {
-                preaddedTasks.put(task.mTaskId, true);
+    void loadRecentTasksIfNeeded(int userId) {
+        AtomicBoolean userLoaded;
+        synchronized (mService.mGlobalLock) {
+            userLoaded = mUsersWithRecentsLoaded.get(userId);
+            if (userLoaded == null) {
+                mUsersWithRecentsLoaded.append(userId, userLoaded = new AtomicBoolean());
             }
         }
+        synchronized (userLoaded) {
+            if (userLoaded.get()) {
+                // The recent tasks of the user are already loaded.
+                return;
+            }
+            // Read task files from storage.
+            final SparseBooleanArray persistedTaskIds =
+                    mTaskPersister.readPersistedTaskIdsFromFileForUser(userId);
+            final TaskPersister.RecentTaskFiles taskFiles = TaskPersister.loadTasksForUser(userId);
+            synchronized (mService.mGlobalLock) {
+                restoreRecentTasksLocked(userId, persistedTaskIds, taskFiles);
+            }
+            userLoaded.set(true);
+        }
+    }
 
-        Slog.i(TAG, "Loading recents for user " + userId + " into memory.");
-        List<Task> tasks = mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks);
+    /** Restores recent tasks from raw data (the files are already read into memory). */
+    private void restoreRecentTasksLocked(int userId, SparseBooleanArray persistedTaskIds,
+            TaskPersister.RecentTaskFiles taskFiles) {
+        mTaskPersister.setPersistedTaskIds(userId, persistedTaskIds);
+        mPersistedTaskIds.put(userId, persistedTaskIds.clone());
+        // Check if any tasks are added before recents is loaded.
+        final IntArray existedTaskIds = new IntArray();
+        for (int i = mTasks.size() - 1; i >= 0; i--) {
+            final Task task = mTasks.get(i);
+            if (task.mUserId == userId && shouldPersistTaskLocked(task)) {
+                existedTaskIds.add(task.mTaskId);
+            }
+        }
+        Slog.i(TAG, "Restoring recents for user " + userId);
+        final ArrayList<Task> tasks = mTaskPersister.restoreTasksForUserLocked(userId, taskFiles,
+                existedTaskIds);
 
         // Tasks are ordered from most recent to least recent. Update the last active time to be
         // in sync with task recency when device reboots, so the most recent task has the
@@ -516,37 +537,34 @@
 
         mTasks.addAll(tasks);
         cleanupLocked(userId);
-        mUsersWithRecentsLoaded.put(userId, true);
 
         // If we have tasks added before loading recents, we need to update persistent task IDs.
-        if (preaddedTasks.size() > 0) {
+        if (existedTaskIds.size() > 0) {
             syncPersistentTaskIdsLocked();
         }
     }
 
-    private void loadPersistedTaskIdsForUserLocked(int userId) {
-        // An empty instead of a null set here means that no persistent taskIds were present
-        // on file when we loaded them.
-        if (mPersistedTaskIds.get(userId) == null) {
-            mPersistedTaskIds.put(userId, mTaskPersister.loadPersistedTaskIdsForUser(userId));
-            Slog.i(TAG, "Loaded persisted task ids for user " + userId);
-        }
+    private boolean isRecentTasksLoaded(int userId) {
+        final AtomicBoolean userLoaded = mUsersWithRecentsLoaded.get(userId);
+        return userLoaded != null && userLoaded.get();
     }
 
     /**
      * @return whether the {@param taskId} is currently in use for the given user.
      */
     boolean containsTaskId(int taskId, int userId) {
-        loadPersistedTaskIdsForUserLocked(userId);
-        return mPersistedTaskIds.get(userId).get(taskId);
+        final SparseBooleanArray taskIds = mPersistedTaskIds.get(userId);
+        return taskIds != null && taskIds.get(taskId);
     }
 
-    /**
-     * @return all the task ids for the user with the given {@param userId}.
-     */
-    SparseBooleanArray getTaskIdsForUser(int userId) {
-        loadPersistedTaskIdsForUserLocked(userId);
-        return mPersistedTaskIds.get(userId);
+    /** Returns all the task ids for the user from {@link #usersWithRecentsLoadedLocked}. */
+    SparseBooleanArray getTaskIdsForLoadedUser(int loadedUserId) {
+        final SparseBooleanArray taskIds = mPersistedTaskIds.get(loadedUserId);
+        if (taskIds == null) {
+            Slog.wtf(TAG, "Loaded user without loaded tasks, userId=" + loadedUserId);
+            return new SparseBooleanArray();
+        }
+        return taskIds;
     }
 
     /**
@@ -565,7 +583,7 @@
     private void syncPersistentTaskIdsLocked() {
         for (int i = mPersistedTaskIds.size() - 1; i >= 0; i--) {
             int userId = mPersistedTaskIds.keyAt(i);
-            if (mUsersWithRecentsLoaded.get(userId)) {
+            if (isRecentTasksLoaded(userId)) {
                 // Recents are loaded only after task ids are loaded. Therefore, the set of taskids
                 // referenced here should not be null.
                 mPersistedTaskIds.valueAt(i).clear();
@@ -621,7 +639,7 @@
         int len = 0;
         for (int i = 0; i < usersWithRecentsLoaded.length; i++) {
             int userId = mUsersWithRecentsLoaded.keyAt(i);
-            if (mUsersWithRecentsLoaded.valueAt(i)) {
+            if (mUsersWithRecentsLoaded.valueAt(i).get()) {
                 usersWithRecentsLoaded[len++] = userId;
             }
         }
@@ -639,7 +657,7 @@
      * @param userId the id of the user
      */
     void unloadUserDataFromMemoryLocked(int userId) {
-        if (mUsersWithRecentsLoaded.get(userId)) {
+        if (isRecentTasksLoaded(userId)) {
             Slog.i(TAG, "Unloading recents for user " + userId + " from memory.");
             mUsersWithRecentsLoaded.delete(userId);
             removeTasksForUserLocked(userId);
@@ -922,11 +940,6 @@
         return mService.mAmInternal.getCurrentProfileIds();
     }
 
-    @VisibleForTesting
-    boolean isUserRunning(int userId, int flags) {
-        return mService.mAmInternal.isUserRunning(userId, flags);
-    }
-
     /**
      * @return the list of recent tasks for presentation.
      */
@@ -942,13 +955,6 @@
     private ArrayList<ActivityManager.RecentTaskInfo> getRecentTasksImpl(int maxNum, int flags,
             boolean getTasksAllowed, int userId, int callingUid) {
         final boolean withExcluded = (flags & RECENT_WITH_EXCLUDED) != 0;
-
-        if (!isUserRunning(userId, FLAG_AND_UNLOCKED)) {
-            Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents");
-            return new ArrayList<>();
-        }
-        loadUserRecentsLocked(userId);
-
         final Set<Integer> includedUsers = getProfileIds(userId);
         includedUsers.add(Integer.valueOf(userId));
 
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index a98b9f7..3ef6eeb 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -44,7 +44,6 @@
 import android.view.WindowManager;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.FastPrintWriter;
 import com.android.server.wm.SurfaceAnimator.AnimationType;
@@ -210,7 +209,7 @@
                 Slog.e(TAG, "Failed to start remote animation", e);
                 onAnimationFinished();
             }
-            if (ProtoLogImpl.isEnabled(WM_DEBUG_REMOTE_ANIMATIONS)) {
+            if (ProtoLog.isEnabled(WM_DEBUG_REMOTE_ANIMATIONS)) {
                 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation(): Notify animation start:");
                 writeStartDebugStatement();
             }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index b562ccf..07a03eb 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2158,7 +2158,11 @@
                     organizedTf.mClearedTaskFragmentForPip = true;
                 }
 
-                transitionController.collect(rootTask);
+                if (isPip2ExperimentEnabled()) {
+                    transitionController.collectExistenceChange(rootTask);
+                } else {
+                    transitionController.collect(rootTask);
+                }
 
                 if (transitionController.isShellTransitionsEnabled()) {
                     // set mode NOW so that when we reparent the activity, it won't be resumed.
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 908cbd3..30134d8 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -336,19 +336,19 @@
     }
 
     @Override
-    public boolean performHapticFeedback(int effectId, boolean always) {
+    public boolean performHapticFeedback(int effectId, boolean always, boolean fromIme) {
         final long ident = Binder.clearCallingIdentity();
         try {
             return mService.mPolicy.performHapticFeedback(mUid, mPackageName,
-                        effectId, always, null);
+                        effectId, always, null, fromIme);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
     }
 
     @Override
-    public void performHapticFeedbackAsync(int effectId, boolean always) {
-        performHapticFeedback(effectId, always);
+    public void performHapticFeedbackAsync(int effectId, boolean always, boolean fromIme) {
+        performHapticFeedback(effectId, always, fromIme);
     }
 
     /* Drag/drop */
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index c3de4d5..d67684c 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -32,7 +32,6 @@
 import android.view.SurfaceControl.Transaction;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 
 import java.io.PrintWriter;
@@ -193,7 +192,7 @@
             return;
         }
         mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
-        if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) {
+        if (ProtoLog.isEnabled(WM_DEBUG_ANIM)) {
             StringWriter sw = new StringWriter();
             PrintWriter pw = new PrintWriter(sw);
             mAnimation.dump(pw, "");
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 2bee095..1353ff0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3750,8 +3750,7 @@
 
                 // Boost the adjacent TaskFragment for dimmer if needed.
                 final TaskFragment taskFragment = wc.asTaskFragment();
-                if (taskFragment != null && taskFragment.isEmbedded()
-                        && taskFragment.isVisibleRequested()) {
+                if (taskFragment != null && taskFragment.isEmbedded()) {
                     final TaskFragment adjacentTf = taskFragment.getAdjacentTaskFragment();
                     if (adjacentTf != null && adjacentTf.shouldBoostDimmer()) {
                         adjacentTf.assignLayer(t, layer++);
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 85d81c4..78ababc 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1881,7 +1881,7 @@
 
             mAtmService.getLifecycleManager().scheduleTransactionItem(prev.app.getThread(),
                     PauseActivityItem.obtain(prev.token, prev.finishing, userLeaving,
-                            prev.configChangeFlags, pauseImmediately, autoEnteringPip));
+                            pauseImmediately, autoEnteringPip));
         } catch (Exception e) {
             // Ignore exception, if process died other code will cleanup.
             Slog.w(TAG, "Exception thrown during pause", e);
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 8d054db..24b533a 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -1197,16 +1197,13 @@
         }
     }
 
-    // TODO(b/204399167): change to push the embedded state to the client side
     @Override
     public boolean isActivityEmbedded(IBinder activityToken) {
         synchronized (mGlobalLock) {
             final ActivityRecord activity = ActivityRecord.forTokenLocked(activityToken);
-            if (activity == null) {
-                return false;
-            }
-            final TaskFragment taskFragment = activity.getOrganizedTaskFragment();
-            return taskFragment != null && taskFragment.isEmbeddedWithBoundsOverride();
+            return activity != null
+                    ? activity.isEmbeddedInHostContainer()
+                    : false;
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java
index 5ec0119..d89dc0b 100644
--- a/services/core/java/com/android/server/wm/TaskPersister.java
+++ b/services/core/java/com/android/server/wm/TaskPersister.java
@@ -27,6 +27,7 @@
 import android.os.SystemClock;
 import android.util.ArraySet;
 import android.util.AtomicFile;
+import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -43,20 +44,20 @@
 
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.List;
 
 /**
  * Persister that saves recent tasks into disk.
@@ -129,11 +130,9 @@
                 ImageWriteQueueItem.class);
     }
 
+    /** Reads task ids from file. This should not be called in lock. */
     @NonNull
-    SparseBooleanArray loadPersistedTaskIdsForUser(int userId) {
-        if (mTaskIdsInFile.get(userId) != null) {
-            return mTaskIdsInFile.get(userId).clone();
-        }
+    SparseBooleanArray readPersistedTaskIdsFromFileForUser(int userId) {
         final SparseBooleanArray persistedTaskIds = new SparseBooleanArray();
         synchronized (mIoLock) {
             BufferedReader reader = null;
@@ -154,11 +153,10 @@
                 IoUtils.closeQuietly(reader);
             }
         }
-        mTaskIdsInFile.put(userId, persistedTaskIds);
-        return persistedTaskIds.clone();
+        Slog.i(TAG, "Loaded persisted task ids for user " + userId);
+        return persistedTaskIds;
     }
 
-
     @VisibleForTesting
     void writePersistedTaskIdsForUser(@NonNull SparseBooleanArray taskIds, int userId) {
         if (userId < 0) {
@@ -183,6 +181,10 @@
         }
     }
 
+    void setPersistedTaskIds(int userId, @NonNull SparseBooleanArray taskIds) {
+        mTaskIdsInFile.put(userId, taskIds);
+    }
+
     void unloadUserDataFromMemory(int userId) {
         mTaskIdsInFile.delete(userId);
     }
@@ -241,7 +243,7 @@
         return item != null ? item.mImage : null;
     }
 
-    private String fileToString(File file) {
+    private static String fileToString(File file) {
         final String newline = System.lineSeparator();
         try {
             BufferedReader reader = new BufferedReader(new FileReader(file));
@@ -272,44 +274,64 @@
         return null;
     }
 
-    List<Task> restoreTasksForUserLocked(final int userId, SparseBooleanArray preaddedTasks) {
-        final ArrayList<Task> tasks = new ArrayList<Task>();
-        ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>();
-
-        File userTasksDir = getUserTasksDir(userId);
-
-        File[] recentFiles = userTasksDir.listFiles();
+    /** Loads task files from disk. This should not be called in lock. */
+    static RecentTaskFiles loadTasksForUser(int userId) {
+        final ArrayList<RecentTaskFile> taskFiles = new ArrayList<>();
+        final File userTasksDir = getUserTasksDir(userId);
+        final File[] recentFiles = userTasksDir.listFiles();
         if (recentFiles == null) {
-            Slog.e(TAG, "restoreTasksForUserLocked: Unable to list files from " + userTasksDir);
+            Slog.i(TAG, "loadTasksForUser: Unable to list files from " + userTasksDir
+                    + " exists=" + userTasksDir.exists());
+            return new RecentTaskFiles(new File[0], taskFiles);
+        }
+        for (File taskFile : recentFiles) {
+            if (!taskFile.getName().endsWith(TASK_FILENAME_SUFFIX)) {
+                continue;
+            }
+            final int taskId;
+            try {
+                taskId = Integer.parseInt(taskFile.getName().substring(
+                        0 /* beginIndex */,
+                        taskFile.getName().length() - TASK_FILENAME_SUFFIX.length()));
+            } catch (NumberFormatException e) {
+                Slog.w(TAG, "Unexpected task file name", e);
+                continue;
+            }
+            try {
+                taskFiles.add(new RecentTaskFile(taskId, taskFile));
+            } catch (IOException e) {
+                Slog.w(TAG, "Failed to read file: " + fileToString(taskFile), e);
+                taskFile.delete();
+            }
+        }
+        return new RecentTaskFiles(recentFiles, taskFiles);
+    }
+
+    /** Restores tasks from raw bytes (no read storage operation). */
+    ArrayList<Task> restoreTasksForUserLocked(int userId, RecentTaskFiles recentTaskFiles,
+            IntArray existedTaskIds) {
+        final ArrayList<Task> tasks = new ArrayList<>();
+        final ArrayList<RecentTaskFile> taskFiles = recentTaskFiles.mLoadedFiles;
+        if (taskFiles.isEmpty()) {
             return tasks;
         }
 
-        for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) {
-            File taskFile = recentFiles[taskNdx];
+        final ArraySet<Integer> recoveredTaskIds = new ArraySet<>();
+        for (int taskNdx = 0; taskNdx < taskFiles.size(); ++taskNdx) {
+            final RecentTaskFile recentTask = taskFiles.get(taskNdx);
+            if (existedTaskIds.contains(recentTask.mTaskId)) {
+                Slog.w(TAG, "Task #" + recentTask.mTaskId
+                        + " has already been created, so skip restoring");
+                continue;
+            }
+            final File taskFile = recentTask.mFile;
             if (DEBUG) {
                 Slog.d(TAG, "restoreTasksForUserLocked: userId=" + userId
                         + ", taskFile=" + taskFile.getName());
             }
 
-            if (!taskFile.getName().endsWith(TASK_FILENAME_SUFFIX)) {
-                continue;
-            }
-            try {
-                final int taskId = Integer.parseInt(taskFile.getName().substring(
-                        0 /* beginIndex */,
-                        taskFile.getName().length() - TASK_FILENAME_SUFFIX.length()));
-                if (preaddedTasks.get(taskId, false)) {
-                    Slog.w(TAG, "Task #" + taskId +
-                            " has already been created so we don't restore again");
-                    continue;
-                }
-            } catch (NumberFormatException e) {
-                Slog.w(TAG, "Unexpected task file name", e);
-                continue;
-            }
-
             boolean deleteFile = false;
-            try (InputStream is = new FileInputStream(taskFile)) {
+            try (InputStream is = recentTask.mXmlContent) {
                 final TypedXmlPullParser in = Xml.resolvePullParser(is);
 
                 int event;
@@ -345,7 +367,7 @@
                                 } else if (userId != task.mUserId) {
                                     // Should not happen.
                                     Slog.wtf(TAG, "Task with userId " + task.mUserId + " found in "
-                                            + userTasksDir.getAbsolutePath());
+                                            + taskFile.getAbsolutePath());
                                 } else {
                                     // Looks fine.
                                     mTaskSupervisor.setNextTaskIdForUser(taskId, userId);
@@ -377,7 +399,7 @@
         }
 
         if (!DEBUG) {
-            removeObsoleteFiles(recoveredTaskIds, userTasksDir.listFiles());
+            removeObsoleteFiles(recoveredTaskIds, recentTaskFiles.mUserTaskFiles);
         }
 
         // Fix up task affiliation from taskIds
@@ -456,7 +478,7 @@
         SparseArray<SparseBooleanArray> changedTaskIdsPerUser = new SparseArray<>();
         synchronized (mService.mGlobalLock) {
             for (int userId : mRecentTasks.usersWithRecentsLoadedLocked()) {
-                SparseBooleanArray taskIdsToSave = mRecentTasks.getTaskIdsForUser(userId);
+                SparseBooleanArray taskIdsToSave = mRecentTasks.getTaskIdsForLoadedUser(userId);
                 SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId);
                 if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIdsToSave)) {
                     continue;
@@ -512,6 +534,30 @@
         return parentDir.isDirectory() || parentDir.mkdir();
     }
 
+    private static class RecentTaskFile {
+        final int mTaskId;
+        final File mFile;
+        final ByteArrayInputStream mXmlContent;
+
+        RecentTaskFile(int taskId, File file) throws IOException {
+            mTaskId = taskId;
+            mFile = file;
+            mXmlContent = new ByteArrayInputStream(Files.readAllBytes(file.toPath()));
+        }
+    }
+
+    static class RecentTaskFiles {
+        /** All files under the user task directory. */
+        final File[] mUserTaskFiles;
+        /** The successfully loaded files. */
+        final ArrayList<RecentTaskFile> mLoadedFiles;
+
+        RecentTaskFiles(File[] userFiles, ArrayList<RecentTaskFile> loadedFiles) {
+            mUserTaskFiles = userFiles;
+            mLoadedFiles = loadedFiles;
+        }
+    }
+
     private static class TaskWriteQueueItem implements PersisterQueue.WriteQueueItem {
         private final ActivityTaskManagerService mService;
         private final Task mTask;
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 001f46d..594043d 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -58,7 +58,6 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.wallpaper.WallpaperCropper.WallpaperCropUtils;
@@ -336,7 +335,7 @@
         for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
             final WallpaperWindowToken token = mWallpaperTokens.get(i);
             token.setVisibility(false);
-            if (ProtoLogImpl.isEnabled(WM_DEBUG_WALLPAPER) && token.isVisible()) {
+            if (ProtoLog.isEnabled(WM_DEBUG_WALLPAPER) && token.isVisible()) {
                 ProtoLog.d(WM_DEBUG_WALLPAPER,
                         "Hiding wallpaper %s from %s target=%s prev=%s callers=%s",
                         token, winGoingAway, mWallpaperTarget, mPrevWallpaperTarget,
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index b43a454..5e7f1cb 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -28,6 +28,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.content.Context;
+import android.os.HandlerExecutor;
 import android.os.Trace;
 import android.util.Slog;
 import android.util.TimeUtils;
@@ -69,6 +70,8 @@
 
     private Choreographer mChoreographer;
 
+    private final HandlerExecutor mExecutor;
+
     /**
      * Indicates whether we have an animation frame callback scheduled, which will happen at
      * vsync-app and then schedule the animation tick at the right time (vsync-sf).
@@ -80,8 +83,7 @@
      * A list of runnable that need to be run after {@link WindowContainer#prepareSurfaces} is
      * executed and the corresponding transaction is closed and applied.
      */
-    private final ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>();
-    private boolean mInExecuteAfterPrepareSurfacesRunnables;
+    private ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>();
 
     private final SurfaceControl.Transaction mTransaction;
 
@@ -92,6 +94,7 @@
         mTransaction = service.mTransactionFactory.get();
         service.mAnimationHandler.runWithScissors(
                 () -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */);
+        mExecutor = new HandlerExecutor(service.mAnimationHandler);
 
         mAnimationFrameCallback = frameTimeNs -> {
             synchronized (mService.mGlobalLock) {
@@ -197,6 +200,19 @@
             updateRunningExpensiveAnimationsLegacy();
         }
 
+        final ArrayList<Runnable> afterPrepareSurfacesRunnables = mAfterPrepareSurfacesRunnables;
+        if (!afterPrepareSurfacesRunnables.isEmpty()) {
+            mAfterPrepareSurfacesRunnables = new ArrayList<>();
+            mTransaction.addTransactionCommittedListener(mExecutor, () -> {
+                synchronized (mService.mGlobalLock) {
+                    // Traverse in order they were added.
+                    for (int i = 0, size = afterPrepareSurfacesRunnables.size(); i < size; i++) {
+                        afterPrepareSurfacesRunnables.get(i).run();
+                    }
+                    afterPrepareSurfacesRunnables.clear();
+                }
+            });
+        }
         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "applyTransaction");
         mTransaction.apply();
         Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
@@ -204,7 +220,6 @@
         ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION animate");
 
         mService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
-        executeAfterPrepareSurfacesRunnables();
 
         if (DEBUG_WINDOW_TRACE) {
             Slog.i(TAG, "!!! animate: exit"
@@ -286,34 +301,10 @@
 
     /**
      * Adds a runnable to be executed after {@link WindowContainer#prepareSurfaces} is called and
-     * the corresponding transaction is closed and applied.
+     * the corresponding transaction is closed, applied, and committed.
      */
     void addAfterPrepareSurfacesRunnable(Runnable r) {
-        // If runnables are already being handled in executeAfterPrepareSurfacesRunnable, then just
-        // immediately execute the runnable passed in.
-        if (mInExecuteAfterPrepareSurfacesRunnables) {
-            r.run();
-            return;
-        }
-
         mAfterPrepareSurfacesRunnables.add(r);
         scheduleAnimation();
     }
-
-    void executeAfterPrepareSurfacesRunnables() {
-
-        // Don't even think about to start recursing!
-        if (mInExecuteAfterPrepareSurfacesRunnables) {
-            return;
-        }
-        mInExecuteAfterPrepareSurfacesRunnables = true;
-
-        // Traverse in order they were added.
-        final int size = mAfterPrepareSurfacesRunnables.size();
-        for (int i = 0; i < size; i++) {
-            mAfterPrepareSurfacesRunnables.get(i).run();
-        }
-        mAfterPrepareSurfacesRunnables.clear();
-        mInExecuteAfterPrepareSurfacesRunnables = false;
-    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 61fde5e..fd0289e 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -113,7 +113,6 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
-import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.wm.SurfaceAnimator.Animatable;
@@ -3410,7 +3409,7 @@
                 // ActivityOption#makeCustomAnimation or WindowManager#overridePendingTransition.
                 a.restrictDuration(MAX_APP_TRANSITION_DURATION);
             }
-            if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) {
+            if (ProtoLog.isEnabled(WM_DEBUG_ANIM)) {
                 ProtoLog.i(WM_DEBUG_ANIM, "Loaded animation %s for %s, duration: %d, stack=%s",
                         a, this, ((a != null) ? a.getDuration() : 0), Debug.getCallers(20));
             }
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 4698b6b..77319cc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -829,20 +829,20 @@
      * Show IME on imeTargetWindow once IME has finished layout.
      *
      * @param imeTargetWindowToken token of the (IME target) window which IME should be shown.
-     * @param statsToken the token tracking the current IME show request or {@code null} otherwise.
+     * @param statsToken the token tracking the current IME request.
      */
     public abstract void showImePostLayout(IBinder imeTargetWindowToken,
-            @Nullable ImeTracker.Token statsToken);
+            @NonNull ImeTracker.Token statsToken);
 
     /**
      * Hide IME using imeTargetWindow when requested.
      *
-     * @param imeTargetWindowToken token of the (IME target) window on which requests hiding IME.
+     * @param imeTargetWindowToken token of the (IME target) window which requests hiding IME.
      * @param displayId the id of the display the IME is on.
-     * @param statsToken the token tracking the current IME hide request or {@code null} otherwise.
+     * @param statsToken the token tracking the current IME request.
      */
     public abstract void hideIme(IBinder imeTargetWindowToken, int displayId,
-            @Nullable ImeTracker.Token statsToken);
+            @NonNull ImeTracker.Token statsToken);
 
     /**
      * Tell window manager about a package that should be running with a restricted range of
@@ -1079,4 +1079,10 @@
      * Moves the current focus to the top activity window if the top activity is embedded.
      */
     public abstract boolean moveFocusToTopEmbeddedWindowIfNeeded();
+
+    /**
+     * Returns an instance of {@link ScreenCapture.ScreenshotHardwareBuffer} containing the current
+     * screenshot.
+     */
+    public abstract ScreenCapture.ScreenshotHardwareBuffer takeAssistScreenshot();
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9b7bc43..ae5a5cb 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -327,8 +327,8 @@
 import com.android.internal.policy.IKeyguardLockedStateListener;
 import com.android.internal.policy.IShortcutService;
 import com.android.internal.policy.KeyInterceptionInfo;
+import com.android.internal.protolog.LegacyProtoLogImpl;
 import com.android.internal.protolog.ProtoLogGroup;
-import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastPrintWriter;
@@ -4081,13 +4081,8 @@
         }
     }
 
-    /**
-     * Takes a snapshot of the screen.  In landscape mode this grabs the whole screen.
-     * In portrait mode, it grabs the upper region of the screen based on the vertical dimension
-     * of the target image.
-     */
-    @Override
-    public boolean requestAssistScreenshot(final IAssistDataReceiver receiver) {
+    @Nullable
+    private ScreenCapture.ScreenshotHardwareBuffer takeAssistScreenshot() {
         if (!checkCallingPermission(READ_FRAME_BUFFER, "requestAssistScreenshot()")) {
             throw new SecurityException("Requires READ_FRAME_BUFFER permission");
         }
@@ -4106,24 +4101,34 @@
             }
         }
 
-        final Bitmap bm;
+        final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer;
         if (captureArgs != null) {
             ScreenCapture.SynchronousScreenCaptureListener syncScreenCapture =
                     ScreenCapture.createSyncCaptureListener();
 
             ScreenCapture.captureLayers(captureArgs, syncScreenCapture);
 
-            final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
-                    syncScreenCapture.getBuffer();
-            bm = screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
+            screenshotBuffer = syncScreenCapture.getBuffer();
         } else {
-            bm = null;
+            screenshotBuffer = null;
         }
 
-        if (bm == null) {
+        if (screenshotBuffer == null) {
             Slog.w(TAG_WM, "Failed to take screenshot");
         }
 
+        return screenshotBuffer;
+    }
+
+    /**
+     * Takes a snapshot of the screen.  In landscape mode this grabs the whole screen.
+     * In portrait mode, it grabs the upper region of the screen based on the vertical dimension
+     * of the target image.
+     */
+    @Override
+    public boolean requestAssistScreenshot(final IAssistDataReceiver receiver) {
+        final ScreenCapture.ScreenshotHardwareBuffer shb = takeAssistScreenshot();
+        final Bitmap bm = shb != null ? shb.asBitmap() : null;
         FgThread.getHandler().post(() -> {
             try {
                 receiver.onHandleAssistScreenshot(bm);
@@ -6701,7 +6706,11 @@
 
     private void dumpLogStatus(PrintWriter pw) {
         pw.println("WINDOW MANAGER LOGGING (dumpsys window logging)");
-        pw.println(ProtoLogImpl.getSingleInstance().getStatus());
+        if (android.tracing.Flags.perfettoProtologTracing()) {
+            pw.println("Deprecated legacy command. Use Perfetto commands instead.");
+            return;
+        }
+        ((LegacyProtoLogImpl) ProtoLog.getSingleInstance()).getStatus();
     }
 
     private void dumpSessionsLocked(PrintWriter pw) {
@@ -8249,12 +8258,17 @@
 
         @Override
         public void showImePostLayout(IBinder imeTargetWindowToken,
-                @Nullable ImeTracker.Token statsToken) {
+                @NonNull ImeTracker.Token statsToken) {
             synchronized (mGlobalLock) {
                 InputTarget imeTarget = getInputTargetFromWindowTokenLocked(imeTargetWindowToken);
                 if (imeTarget == null) {
+                    ImeTracker.forLogging().onFailed(statsToken,
+                            ImeTracker.PHASE_WM_HAS_IME_INSETS_CONTROL_TARGET);
                     return;
                 }
+                ImeTracker.forLogging().onProgress(statsToken,
+                        ImeTracker.PHASE_WM_HAS_IME_INSETS_CONTROL_TARGET);
+
                 Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "WMS.showImePostLayout", 0);
                 final InsetsControlTarget controlTarget = imeTarget.getImeControlTarget();
                 imeTarget = controlTarget.getWindow();
@@ -8269,7 +8283,7 @@
 
         @Override
         public void hideIme(IBinder imeTargetWindowToken, int displayId,
-                @Nullable ImeTracker.Token statsToken) {
+                @NonNull ImeTracker.Token statsToken) {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WMS.hideIme");
             synchronized (mGlobalLock) {
                 WindowState imeTarget = mWindowMap.get(imeTargetWindowToken);
@@ -8684,6 +8698,12 @@
                 return false;
             }
         }
+
+        @Override
+        public ScreenCapture.ScreenshotHardwareBuffer takeAssistScreenshot() {
+            // WMS.takeAssistScreenshot takes care of the locking.
+            return WindowManagerService.this.takeAssistScreenshot();
+        }
     }
 
     private final class ImeTargetVisibilityPolicyImpl extends ImeTargetVisibilityPolicy {
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 8fad950..0b29f96 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -48,7 +48,9 @@
 import android.view.ViewDebug;
 
 import com.android.internal.os.ByteTransferPipe;
-import com.android.internal.protolog.ProtoLogImpl;
+import com.android.internal.protolog.LegacyProtoLogImpl;
+import com.android.internal.protolog.common.IProtoLog;
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.server.IoThread;
 import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
 import com.android.server.wm.LetterboxConfiguration.LetterboxHorizontalReachabilityPosition;
@@ -107,11 +109,19 @@
                     // trace files can be written.
                     return mInternal.mWindowTracing.onShellCommand(this);
                 case "logging":
-                    int result = ProtoLogImpl.getSingleInstance().onShellCommand(this);
-                    if (result != 0) {
-                        pw.println("Not handled, please use "
-                                + "`adb shell dumpsys activity service SystemUIService WMShell` "
-                                + "if you are looking for ProtoLog in WMShell");
+                    IProtoLog instance = ProtoLog.getSingleInstance();
+                    int result = 0;
+                    if (instance instanceof LegacyProtoLogImpl) {
+                        result = ((LegacyProtoLogImpl) instance).onShellCommand(this);
+                        if (result != 0) {
+                            pw.println("Not handled, please use "
+                                    + "`adb shell dumpsys activity service SystemUIService "
+                                    + "WMShell` if you are looking for ProtoLog in WMShell");
+                        }
+                    } else {
+                        result = -1;
+                        pw.println("Command not supported. "
+                                + "Only supported when using legacy ProtoLog.");
                     }
                     return result;
                 case "user-rotation":
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index d6fc01a..a7eb444 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -329,15 +329,7 @@
                                         deferred);
                                 wctApplied.meet();
                                 if (needsSetReady) {
-                                    // TODO(b/294925498): Remove this once we have accurate ready
-                                    //                    tracking.
-                                    if (hasActivityLaunch(wct) && !mService.mRootWindowContainer
-                                            .allPausedActivitiesComplete()) {
-                                        // WCT is launching an activity, so we need to wait for its
-                                        // lifecycle events.
-                                        return;
-                                    }
-                                    nextTransition.setAllReady();
+                                    setAllReadyIfNeeded(nextTransition, wct);
                                 }
                             });
                     return nextTransition.getToken();
@@ -390,7 +382,7 @@
         }
     }
 
-    private static boolean hasActivityLaunch(WindowContainerTransaction wct) {
+    private static boolean hasActivityLaunch(@NonNull WindowContainerTransaction wct) {
         for (int i = 0; i < wct.getHierarchyOps().size(); ++i) {
             if (wct.getHierarchyOps().get(i).getType() == HIERARCHY_OP_TYPE_LAUNCH_TASK) {
                 return true;
@@ -399,6 +391,46 @@
         return false;
     }
 
+    private boolean isCreatedTaskFragmentReady(@NonNull WindowContainerTransaction wct) {
+        for (int i = 0; i < wct.getHierarchyOps().size(); ++i) {
+            final WindowContainerTransaction.HierarchyOp op = wct.getHierarchyOps().get(i);
+            if (op.getType() != HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION
+                    || op.getTaskFragmentOperation().getOpType()
+                    != OP_TYPE_CREATE_TASK_FRAGMENT) {
+                continue;
+            }
+            final IBinder tfToken = op.getTaskFragmentOperation()
+                    .getTaskFragmentCreationParams().getFragmentToken();
+            final TaskFragment taskFragment = getTaskFragment(tfToken);
+            if (taskFragment != null && !taskFragment.isReadyToTransit()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void setAllReadyIfNeeded(@NonNull Transition transition,
+            @NonNull WindowContainerTransaction wct) {
+        // TODO(b/294925498): Remove this once we have accurate ready tracking.
+        if (hasActivityLaunch(wct) && !mService.mRootWindowContainer
+                .allPausedActivitiesComplete()) {
+            // WCT is launching an activity, so we need to wait for its
+            // lifecycle events.
+            return;
+        }
+        if (!isCreatedTaskFragmentReady(wct)) {
+            // When the organizer intercepts a #startActivity, it will create an empty TaskFragment
+            // for that specific incoming starting activity. We don't want to set all ready here,
+            // because we requires that #startActivity to be included in this transition, and NOT be
+            // in its own transition.
+            // TODO(b/232042367): explicitly ensure the #startActivity and this transaction are in
+            // the same transition instead of relying on this possible racing condition.
+            return;
+        }
+
+        transition.setAllReady();
+    }
+
     @Override
     public int startLegacyTransition(int type, @NonNull RemoteAnimationAdapter adapter,
             @NonNull IWindowContainerTransactionCallback callback,
@@ -529,7 +561,7 @@
                 }
                 mTransitionController.requestStartTransition(transition, null /* startTask */,
                         remoteTransition, null /* displayChange */);
-                transition.setAllReady();
+                setAllReadyIfNeeded(transition, wct);
             };
             mTransitionController.startCollectOrQueue(transition, doApply);
         } finally {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 90f5b62..18ac0e7 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -245,7 +245,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.KeyInterceptionInfo;
-import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.ToBooleanFunction;
@@ -2042,6 +2041,13 @@
         if (!isVisible()) {
             return;
         }
+        final WallpaperWindowToken wallpaperToken = mToken.asWallpaperToken();
+        if (wallpaperToken != null) {
+            if (wallpaperToken.hasVisibleNotDrawnWallpaper()) {
+                outWaitingForDrawn.add(this);
+            }
+            return;
+        }
         if (mActivityRecord != null) {
             if (!mActivityRecord.isVisibleRequested()) return;
             if (mActivityRecord.allDrawn) {
@@ -4681,7 +4687,7 @@
     }
 
     void onExitAnimationDone() {
-        if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) {
+        if (ProtoLog.isEnabled(WM_DEBUG_ANIM)) {
             final AnimationAdapter animationAdapter = mSurfaceAnimator.getAnimation();
             StringWriter sw = new StringWriter();
             if (animationAdapter != null) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 6428591..7f7c249 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -60,7 +60,6 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 
-import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.server.policy.WindowManagerPolicy;
 
@@ -584,7 +583,7 @@
                             mWin.mAttrs, attr, TRANSIT_OLD_NONE);
                 }
             }
-            if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) {
+            if (ProtoLog.isEnabled(WM_DEBUG_ANIM)) {
                 ProtoLog.v(WM_DEBUG_ANIM, "applyAnimation: win=%s"
                         + " anim=%d attr=0x%x a=%s transit=%d type=%d isEntrance=%b Callers %s",
                         this, anim, attr, a, transit, mAttrType, isEntrance, Debug.getCallers(20));
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index 416d042..6d5fc80 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -35,7 +35,9 @@
 import android.util.proto.ProtoOutputStream;
 import android.view.Choreographer;
 
-import com.android.internal.protolog.ProtoLogImpl;
+import com.android.internal.protolog.LegacyProtoLogImpl;
+import com.android.internal.protolog.common.IProtoLog;
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.TraceBuffer;
 
 import java.io.File;
@@ -77,6 +79,8 @@
     private volatile boolean mEnabledLockFree;
     private boolean mScheduled;
 
+    private final IProtoLog mProtoLog;
+
     static WindowTracing createDefaultAndStartLooper(WindowManagerService service,
             Choreographer choreographer) {
         File file = new File(TRACE_FILENAME);
@@ -96,6 +100,7 @@
         mTraceFile = file;
         mBuffer = new TraceBuffer(bufferCapacity);
         setLogLevel(WindowTraceLogLevel.TRIM, null /* pw */);
+        mProtoLog = ProtoLog.getSingleInstance();
     }
 
     void startTrace(@Nullable PrintWriter pw) {
@@ -104,7 +109,6 @@
             return;
         }
         synchronized (mEnabledLock) {
-            ProtoLogImpl.getSingleInstance().startProtoLog(pw);
             logAndPrintln(pw, "Start tracing to " + mTraceFile + ".");
             mBuffer.resetBuffer();
             mEnabled = mEnabledLockFree = true;
@@ -132,7 +136,6 @@
             writeTraceToFileLocked();
             logAndPrintln(pw, "Trace written to " + mTraceFile + ".");
         }
-        ProtoLogImpl.getSingleInstance().stopProtoLog(pw, true);
     }
 
     /**
@@ -152,11 +155,15 @@
             logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush.");
             writeTraceToFileLocked();
             logAndPrintln(pw, "Trace written to " + mTraceFile + ".");
-            ProtoLogImpl.getSingleInstance().stopProtoLog(pw, true);
+            if (!android.tracing.Flags.perfettoProtologTracing()) {
+                ((LegacyProtoLogImpl) mProtoLog).stopProtoLog(pw, true);
+            }
             logAndPrintln(pw, "Start tracing to " + mTraceFile + ".");
             mBuffer.resetBuffer();
             mEnabled = mEnabledLockFree = true;
-            ProtoLogImpl.getSingleInstance().startProtoLog(pw);
+            if (!android.tracing.Flags.perfettoProtologTracing()) {
+                ((LegacyProtoLogImpl) mProtoLog).startProtoLog(pw);
+            }
         }
     }
 
diff --git a/services/core/jni/com_android_server_accessibility_BrailleDisplayConnection.cpp b/services/core/jni/com_android_server_accessibility_BrailleDisplayConnection.cpp
index 9a509a7..c337523 100644
--- a/services/core/jni/com_android_server_accessibility_BrailleDisplayConnection.cpp
+++ b/services/core/jni/com_android_server_accessibility_BrailleDisplayConnection.cpp
@@ -40,7 +40,7 @@
 } // anonymous namespace
 
 static jint com_android_server_accessibility_BrailleDisplayConnection_getHidrawDescSize(
-        JNIEnv* env, jobject thiz, int fd) {
+        JNIEnv* env, jclass /*clazz*/, int fd) {
     int size = 0;
     if (ioctl(fd, HIDIOCGRDESCSIZE, &size) < 0) {
         return -1;
@@ -49,7 +49,7 @@
 }
 
 static jbyteArray com_android_server_accessibility_BrailleDisplayConnection_getHidrawDesc(
-        JNIEnv* env, jobject thiz, int fd, int descSize) {
+        JNIEnv* env, jclass /*clazz*/, int fd, int descSize) {
     struct hidraw_report_descriptor desc;
     desc.size = descSize;
     if (ioctl(fd, HIDIOCGRDESC, &desc) < 0) {
@@ -63,9 +63,8 @@
     return result;
 }
 
-static jstring com_android_server_accessibility_BrailleDisplayConnection_getHidrawUniq(JNIEnv* env,
-                                                                                       jobject thiz,
-                                                                                       int fd) {
+static jstring com_android_server_accessibility_BrailleDisplayConnection_getHidrawUniq(
+        JNIEnv* env, jclass /*clazz*/, int fd) {
     char buf[UNIQ_SIZE_MAX];
     if (ioctl(fd, HIDIOCGRAWUNIQ(UNIQ_SIZE_MAX), buf) < 0) {
         return nullptr;
@@ -74,9 +73,8 @@
     return env->NewStringUTF(buf);
 }
 
-static jint com_android_server_accessibility_BrailleDisplayConnection_getHidrawBusType(JNIEnv* env,
-                                                                                       jobject thiz,
-                                                                                       int fd) {
+static jint com_android_server_accessibility_BrailleDisplayConnection_getHidrawBusType(
+        JNIEnv* env, jclass /*clazz*/, int fd) {
     struct hidraw_devinfo info;
     if (ioctl(fd, HIDIOCGRAWINFO, &info) < 0) {
         return -1;
diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
index f5e6c45..f47a59d 100644
--- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp
+++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
@@ -370,6 +370,7 @@
         return JNI_FALSE;
     }
     vibrator::Info info = wrapper->getVibratorInfo();
+    info.logFailures();
 
     if (info.capabilities.isOk()) {
         env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setCapabilities,
@@ -443,7 +444,7 @@
     env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setFrequencyProfile,
                           frequencyProfile);
 
-    return info.isFailedLogged("vibratorGetInfo") ? JNI_FALSE : JNI_TRUE;
+    return info.shouldRetry() ? JNI_FALSE : JNI_TRUE;
 }
 
 static const JNINativeMethod method_table[] = {
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
index 9d45cfb..f5e1e41 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
@@ -18,7 +18,6 @@
 import static android.credentials.selection.Constants.EXTRA_FINAL_RESPONSE_RECEIVER;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
@@ -114,8 +113,8 @@
 
     /** Creates intent that is ot be invoked to cancel an in-progress UI session. */
     public Intent createCancelIntent(IBinder requestId, String packageName) {
-        return IntentFactory.createCancelUiIntent(requestId, /*shouldShowCancellationUi=*/ true,
-                packageName);
+        return IntentFactory.createCancelUiIntent(mContext, requestId,
+                /*shouldShowCancellationUi=*/ true, packageName);
     }
 
     /**
@@ -161,26 +160,6 @@
      */
     public PendingIntent createPendingIntent(
             RequestInfo requestInfo, ArrayList<ProviderData> providerDataList) {
-        return createPendingIntent(requestInfo, providerDataList, /*forAutofill=*/ false);
-    }
-
-    /**
-     * Creates a {@link PendingIntent} to be used to invoke the credential manager selector UI,
-     * by the calling app process. This intent is invoked from the Autofill flow, when the user
-     * requests to bring up the 'All Options' page of the credential bottom-sheet. When the user
-     * clicks on the pinned entry, the intent will bring up the 'All Options' page of the
-     * bottom-sheet. The provider data list is processed by the credential autofill service for
-     * each autofill id and passed in as an auth extra.
-     *
-     * @param requestInfo            the information about the request
-     */
-    public PendingIntent createPendingIntentForAutofill(RequestInfo requestInfo) {
-        return createPendingIntent(requestInfo, /*providerDataList=*/ null, /*forAutofill=*/ true);
-    }
-
-    private PendingIntent createPendingIntent(
-            RequestInfo requestInfo, @Nullable ArrayList<ProviderData> providerDataList,
-            boolean forAutofill) {
         List<CredentialProviderInfo> allProviders =
                 CredentialProviderInfoFactory.getCredentialProviderServices(
                         mContext,
@@ -196,15 +175,9 @@
                         disabledProvider.getComponentName().flattenToString())).toList();
 
         Intent intent;
-        if (forAutofill) {
-            intent = IntentFactory.createCredentialSelectorIntentForAutofill(
-                    mContext, requestInfo, new ArrayList<>(disabledProviderDataList),
-                    mResultReceiver);
-        } else {
-            intent = IntentFactory.createCredentialSelectorIntent(
-                    mContext, requestInfo, providerDataList,
-                    new ArrayList<>(disabledProviderDataList), mResultReceiver);
-        }
+        intent = IntentFactory.createCredentialSelectorIntent(
+                mContext, requestInfo, providerDataList,
+                new ArrayList<>(disabledProviderDataList), mResultReceiver);
         intent.setAction(UUID.randomUUID().toString());
         //TODO: Create unique pending intent using request code and cancel any pre-existing pending
         // intents
@@ -213,4 +186,21 @@
                 PendingIntent.FLAG_MUTABLE, /*options=*/null,
                 UserHandle.of(mUserId));
     }
+
+    /**
+     * Creates an {@link Intent} to be used to invoke the credential manager selector UI,
+     * by the calling app process. This intent is invoked from the Autofill flow, when the user
+     * requests to bring up the 'All Options' page of the credential bottom-sheet. When the user
+     * clicks on the pinned entry, the intent will bring up the 'All Options' page of the
+     * bottom-sheet. The provider data list is processed by the credential autofill service for
+     * each autofill id and passed in as extras in the pending intent set as authentication
+     * of the pinned entry.
+     *
+     * @param requestInfo            the information about the request
+     */
+    public Intent createIntentForAutofill(RequestInfo requestInfo) {
+        return IntentFactory.createCredentialSelectorIntentForAutofill(
+                mContext, requestInfo, new ArrayList<>(),
+                mResultReceiver);
+    }
 }
diff --git a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
index 723c52f..eff53de 100644
--- a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.credentials.Constants;
 import android.credentials.CredentialProviderInfo;
 import android.credentials.GetCandidateCredentialsException;
@@ -40,6 +41,8 @@
 import android.service.credentials.PermissionUtils;
 import android.util.Slog;
 
+import com.android.server.credentials.metrics.ApiStatus;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -114,8 +117,7 @@
             return;
         }
 
-        cancelExistingPendingIntent();
-        mPendingIntent = mCredentialManagerUi.createPendingIntentForAutofill(
+        Intent intent = mCredentialManagerUi.createIntentForAutofill(
                 RequestInfo.newGetRequestInfo(
                         mRequestId, mClientRequest, mClientAppInfo.getPackageName(),
                         PermissionUtils.hasPermission(mContext, mClientAppInfo.getPackageName(),
@@ -129,7 +131,7 @@
 
         try {
             invokeClientCallbackSuccess(new GetCandidateCredentialsResponse(
-                    candidateProviderDataList, mPendingIntent));
+                    candidateProviderDataList, intent));
         } catch (RemoteException e) {
             Slog.e(TAG, "Issue while responding to client with error : " + e);
         }
@@ -150,7 +152,8 @@
     @Override
     public void onFinalErrorReceived(ComponentName componentName, String errorType,
             String message) {
-        respondToClientWithErrorAndFinish(errorType, message);
+        Slog.d(TAG, "onFinalErrorReceived");
+        respondToFinalReceiverWithFailureAndFinish(this.mFinalResponseReceiver, errorType, message);
     }
 
     @Override
@@ -163,6 +166,13 @@
             message = "The UI was interrupted - please try again.";
         }
         mRequestSessionMetric.collectFrameworkException(exception);
+        respondToFinalReceiverWithFailureAndFinish(finalResponseReceiver, exception, message);
+    }
+
+    private void respondToFinalReceiverWithFailureAndFinish(
+            ResultReceiver finalResponseReceiver,
+            String exception, String message
+    ) {
         if (finalResponseReceiver != null) {
             Bundle resultData = new Bundle();
             resultData.putStringArray(
@@ -170,16 +180,16 @@
                     new String[] {exception, message});
             finalResponseReceiver.send(Constants.FAILURE_CREDMAN_SELECTOR, resultData);
         } else {
-            respondToClientWithErrorAndFinish(exception, message);
+            Slog.w(TAG, "onUiCancellation called but finalResponseReceiver not found");
         }
+        finishSession(/*propagateCancellation=*/false, ApiStatus.FAILURE.getMetricCode());
     }
 
     @Override
     public void onUiSelectorInvocationFailure() {
         String exception = GetCandidateCredentialsException.TYPE_NO_CREDENTIAL;
         mRequestSessionMetric.collectFrameworkException(exception);
-        respondToClientWithErrorAndFinish(exception,
-                "No credentials available.");
+        // TODO(): Propagate through final receiver
     }
 
     @Override
@@ -213,9 +223,10 @@
             resultData.putParcelable(
                     CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE, response);
             mFinalResponseReceiver.send(Constants.SUCCESS_CREDMAN_SELECTOR, resultData);
-            finishSession(/*propagateCancellation=*/ false);
+            finishSession(/*propagateCancellation=*/ false, ApiStatus.SUCCESS.getMetricCode());
         } else {
             Slog.w(TAG, "onFinalResponseReceived result receiver not found for pinned entry");
+            finishSession(/*propagateCancellation=*/ false, ApiStatus.FAILURE.getMetricCode());
         }
     }
 
diff --git a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
index 21ac9e4..bc8c2b0 100644
--- a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
+++ b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
@@ -82,7 +82,7 @@
         if (resultData == null) {
             return null;
         }
-        return resultData.getParcelableExtra(
+        return resultData.getSerializableExtra(
                 CredentialProviderService.EXTRA_CREATE_CREDENTIAL_EXCEPTION,
                 CreateCredentialException.class);
     }
@@ -94,7 +94,7 @@
         if (resultData == null) {
             return null;
         }
-        return resultData.getParcelableExtra(
+        return resultData.getSerializableExtra(
                 CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION,
                 GetCredentialException.class);
     }
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index fa63bc8..cad9a09 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -93,7 +93,7 @@
         android.credentials.GetCredentialRequest filteredRequest =
                 filterOptions(providerInfo.getCapabilities(),
                         getRequestSession.mClientRequest,
-                        providerInfo);
+                        providerInfo, getRequestSession.mHybridService);
         if (filteredRequest != null) {
             Map<String, CredentialOption> beginGetOptionToCredentialOptionMap =
                     new HashMap<>();
@@ -129,7 +129,7 @@
         android.credentials.GetCredentialRequest filteredRequest =
                 filterOptions(providerInfo.getCapabilities(),
                         getRequestSession.mClientRequest,
-                        providerInfo);
+                        providerInfo, getRequestSession.mHybridService);
         if (filteredRequest != null) {
             Map<String, CredentialOption> beginGetOptionToCredentialOptionMap =
                     new HashMap<>();
@@ -179,9 +179,19 @@
     private static android.credentials.GetCredentialRequest filterOptions(
             List<String> providerCapabilities,
             android.credentials.GetCredentialRequest clientRequest,
-            CredentialProviderInfo info
-    ) {
+            CredentialProviderInfo info,
+            String hybridService) {
         Slog.i(TAG, "Filtering request options for: " + info.getComponentName());
+        if (android.credentials.flags.Flags.hybridFilterFixEnabled()) {
+            ComponentName hybridComponentName = ComponentName.unflattenFromString(hybridService);
+            if (hybridComponentName != null && hybridComponentName
+                    .equals(info.getComponentName())) {
+                Slog.i(TAG, "Skipping filtering of options for hybrid service");
+                return clientRequest;
+            }
+            Slog.w(TAG, "Could not parse hybrid service while filtering options");
+        }
+
         List<CredentialOption> filteredOptions = new ArrayList<>();
         for (CredentialOption option : clientRequest.getCredentialOptions()) {
             if (providerCapabilities.contains(option.getType())
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index 633c9c4..a5b9aa6 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -175,7 +175,7 @@
                 () -> {
                     Slog.d(TAG, "Cancellation invoked from the client - clearing session");
                     boolean isUiActive = maybeCancelUi();
-                    finishSession(!isUiActive);
+                    finishSession(!isUiActive, ApiStatus.CLIENT_CANCELED.getMetricCode());
                 }
         );
     }
@@ -231,7 +231,8 @@
             return;
         }
         if (isSessionCancelled()) {
-            finishSession(/*propagateCancellation=*/true);
+            finishSession(/*propagateCancellation=*/true,
+                    ApiStatus.CLIENT_CANCELED.getMetricCode());
             return;
         }
         String providerId = selection.getProviderId();
@@ -257,11 +258,12 @@
         }
     }
 
-    protected void finishSession(boolean propagateCancellation) {
+    protected void finishSession(boolean propagateCancellation, int apiStatus) {
         Slog.i(TAG, "finishing session with propagateCancellation " + propagateCancellation);
         if (propagateCancellation) {
             mProviders.values().forEach(ProviderSession::cancelProviderRemoteSession);
         }
+        mRequestSessionMetric.logApiCalledAtFinish(apiStatus);
         mRequestSessionStatus = RequestSessionStatus.COMPLETE;
         mProviders.clear();
         clearRequestSessionLocked();
@@ -326,7 +328,8 @@
         mRequestSessionMetric.logCandidatePhaseMetrics(mProviders);
 
         if (isSessionCancelled()) {
-            finishSession(/*propagateCancellation=*/true);
+            finishSession(/*propagateCancellation=*/true,
+                    ApiStatus.CLIENT_CANCELED.getMetricCode());
             return providerDataList;
         }
 
@@ -353,23 +356,20 @@
             return;
         }
         if (isSessionCancelled()) {
-            mRequestSessionMetric.logApiCalledAtFinish(
-                    /*apiStatus=*/ ApiStatus.CLIENT_CANCELED.getMetricCode());
-            finishSession(/*propagateCancellation=*/true);
+            finishSession(/*propagateCancellation=*/true,
+                    ApiStatus.CLIENT_CANCELED.getMetricCode());
             return;
         }
         try {
             invokeClientCallbackSuccess(response);
-            mRequestSessionMetric.logApiCalledAtFinish(
-                    /*apiStatus=*/ ApiStatus.SUCCESS.getMetricCode());
+            finishSession(/*propagateCancellation=*/false,
+                    ApiStatus.SUCCESS.getMetricCode());
         } catch (RemoteException e) {
             mRequestSessionMetric.collectFinalPhaseProviderMetricStatus(
                     /*has_exception=*/ true, ProviderStatusForMetrics.FINAL_FAILURE);
             Slog.e(TAG, "Issue while responding to client with a response : " + e);
-            mRequestSessionMetric.logApiCalledAtFinish(
-                    /*apiStatus=*/ ApiStatus.FAILURE.getMetricCode());
+            finishSession(/*propagateCancellation=*/false, ApiStatus.FAILURE.getMetricCode());
         }
-        finishSession(/*propagateCancellation=*/false);
     }
 
     /**
@@ -387,9 +387,7 @@
             return;
         }
         if (isSessionCancelled()) {
-            mRequestSessionMetric.logApiCalledAtFinish(
-                    /*apiStatus=*/ ApiStatus.CLIENT_CANCELED.getMetricCode());
-            finishSession(/*propagateCancellation=*/true);
+            finishSession(/*propagateCancellation=*/true, ApiStatus.CLIENT_CANCELED.getMetricCode());
             return;
         }
 
@@ -399,8 +397,14 @@
             Slog.e(TAG, "Issue while responding to client with error : " + e);
         }
         boolean isUserCanceled = errorType.contains(MetricUtilities.USER_CANCELED_SUBSTRING);
-        mRequestSessionMetric.logFailureOrUserCancel(isUserCanceled);
-        finishSession(/*propagateCancellation=*/false);
+        if (isUserCanceled) {
+            mRequestSessionMetric.setHasExceptionFinalPhase(/* has_exception */ false);
+            finishSession(/*propagateCancellation=*/false,
+                    ApiStatus.USER_CANCELED.getMetricCode());
+        } else {
+            finishSession(/*propagateCancellation=*/false,
+                    ApiStatus.FAILURE.getMetricCode());
+        }
     }
 
     /**
@@ -419,7 +423,7 @@
         @Override
         public void binderDied() {
             Slog.d(TAG, "Client binder died - clearing session");
-            finishSession(isUiWaitingForData());
+            finishSession(isUiWaitingForData(), ApiStatus.CLIENT_CANCELED.getMetricCode());
         }
     }
 }
diff --git a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
index 8adcfbc..a77bd3e 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
@@ -247,7 +247,7 @@
      *
      * @param exceptionBitFinalPhase represents if the final phase provider had an exception
      */
-    private void setHasExceptionFinalPhase(boolean exceptionBitFinalPhase) {
+    public void setHasExceptionFinalPhase(boolean exceptionBitFinalPhase) {
         try {
             mChosenProviderFinalPhaseMetric.setHasException(exceptionBitFinalPhase);
         } catch (Exception e) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index 12f4407..6aeb4fd5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -225,7 +225,7 @@
 
         synchronized (mLock) {
             PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId);
-            if (Flags.devicePolicySizeTrackingEnabled() && false) {
+            if (Flags.devicePolicySizeTrackingInternalEnabled()) {
                 if (!handleAdminPolicySizeLimit(localPolicyState, enforcingAdmin, value,
                         policyDefinition, userId)) {
                     return;
@@ -350,7 +350,7 @@
             }
             PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId);
 
-            if (Flags.devicePolicySizeTrackingEnabled() && false) {
+            if (Flags.devicePolicySizeTrackingInternalEnabled()) {
                 decreasePolicySizeForAdmin(localPolicyState, enforcingAdmin);
             }
 
@@ -496,7 +496,7 @@
 
         synchronized (mLock) {
             PolicyState<V> globalPolicyState = getGlobalPolicyStateLocked(policyDefinition);
-            if (Flags.devicePolicySizeTrackingEnabled() && false) {
+            if (Flags.devicePolicySizeTrackingInternalEnabled()) {
                 if (!handleAdminPolicySizeLimit(globalPolicyState, enforcingAdmin, value,
                         policyDefinition, UserHandle.USER_ALL)) {
                     return;
@@ -568,7 +568,7 @@
         synchronized (mLock) {
             PolicyState<V> policyState = getGlobalPolicyStateLocked(policyDefinition);
 
-            if (Flags.devicePolicySizeTrackingEnabled() && false) {
+            if (Flags.devicePolicySizeTrackingInternalEnabled()) {
                 decreasePolicySizeForAdmin(policyState, enforcingAdmin);
             }
 
@@ -1892,7 +1892,7 @@
 
         private void writeEnforcingAdminSizeInner(TypedXmlSerializer serializer)
                 throws IOException {
-            if (Flags.devicePolicySizeTrackingEnabled() && false) {
+            if (Flags.devicePolicySizeTrackingInternalEnabled()) {
                 if (mAdminPolicySize != null) {
                     for (int i = 0; i < mAdminPolicySize.size(); i++) {
                         int userId = mAdminPolicySize.keyAt(i);
@@ -1916,7 +1916,7 @@
 
         private void writeMaxPolicySizeInner(TypedXmlSerializer serializer)
                 throws IOException {
-            if (!Flags.devicePolicySizeTrackingEnabled() || true) {
+            if (!Flags.devicePolicySizeTrackingInternalEnabled()) {
                 return;
             }
             serializer.startTag(/* namespace= */ null, TAG_MAX_POLICY_SIZE_LIMIT);
@@ -2081,7 +2081,7 @@
 
         private void readMaxPolicySizeInner(TypedXmlPullParser parser)
                 throws XmlPullParserException, IOException {
-            if (!Flags.devicePolicySizeTrackingEnabled() || true) {
+            if (!Flags.devicePolicySizeTrackingInternalEnabled()) {
                 return;
             }
             mPolicySizeLimit = parser.getAttributeInt(/* namespace= */ null, ATTR_POLICY_SUM_SIZE);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 0f97f4a..80046b60 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -27,6 +27,7 @@
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_AIRPLANE_MODE;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_APP_RESTRICTIONS;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ASSIST_CONTENT;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_AUDIO_OUTPUT;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_AUTOFILL;
@@ -83,7 +84,6 @@
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_TIME;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER;
-import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ASSIST_CONTENT;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_VPN;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WALLPAPER;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WIFI;
@@ -196,11 +196,11 @@
 import static android.app.admin.DevicePolicyManager.STATUS_DEVICE_ADMIN_NOT_SUPPORTED;
 import static android.app.admin.DevicePolicyManager.STATUS_HAS_DEVICE_OWNER;
 import static android.app.admin.DevicePolicyManager.STATUS_HAS_PAIRED;
+import static android.app.admin.DevicePolicyManager.STATUS_HEADLESS_ONLY_SYSTEM_USER;
 import static android.app.admin.DevicePolicyManager.STATUS_HEADLESS_SYSTEM_USER_MODE_NOT_SUPPORTED;
 import static android.app.admin.DevicePolicyManager.STATUS_MANAGED_USERS_NOT_SUPPORTED;
 import static android.app.admin.DevicePolicyManager.STATUS_NONSYSTEM_USER_EXISTS;
 import static android.app.admin.DevicePolicyManager.STATUS_NOT_SYSTEM_USER;
-import static android.app.admin.DevicePolicyManager.STATUS_HEADLESS_ONLY_SYSTEM_USER;
 import static android.app.admin.DevicePolicyManager.STATUS_OK;
 import static android.app.admin.DevicePolicyManager.STATUS_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS;
 import static android.app.admin.DevicePolicyManager.STATUS_SYSTEM_USER;
@@ -12062,7 +12062,7 @@
         }
 
         if (packageList != null) {
-            if (!Flags.devicePolicySizeTrackingEnabled()) {
+            if (!Flags.devicePolicySizeTrackingInternalEnabled()) {
                 for (String pkg : packageList) {
                     PolicySizeVerifier.enforceMaxPackageNameLength(pkg);
                 }
@@ -13771,7 +13771,7 @@
             return;
         }
 
-        if (!Flags.devicePolicySizeTrackingEnabled()) {
+        if (!Flags.devicePolicySizeTrackingInternalEnabled()) {
             PolicySizeVerifier.enforceMaxStringLength(accountType, "account type");
         }
 
@@ -14385,7 +14385,7 @@
     public void setLockTaskPackages(ComponentName who, String callerPackageName, String[] packages)
             throws SecurityException {
         Objects.requireNonNull(packages, "packages is null");
-        if (!Flags.devicePolicySizeTrackingEnabled()) {
+        if (!Flags.devicePolicySizeTrackingInternalEnabled()) {
             for (String pkg : packages) {
                 PolicySizeVerifier.enforceMaxPackageNameLength(pkg);
             }
@@ -24235,7 +24235,7 @@
 
     @Override
     public void setMaxPolicyStorageLimit(String callerPackageName, int storageLimit) {
-        if (!Flags.devicePolicySizeTrackingEnabled() || true) {
+        if (!Flags.devicePolicySizeTrackingInternalEnabled()) {
             return;
         }
         CallerIdentity caller = getCallerIdentity(callerPackageName);
@@ -24247,7 +24247,7 @@
 
     @Override
     public int getMaxPolicyStorageLimit(String callerPackageName) {
-        if (!Flags.devicePolicySizeTrackingEnabled() || true) {
+        if (!Flags.devicePolicySizeTrackingInternalEnabled()) {
             return -1;
         }
         CallerIdentity caller = getCallerIdentity(callerPackageName);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
index df7f308..1000bfa 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
@@ -53,7 +53,17 @@
         TelephonyManager telephonyService = context.getSystemService(TelephonyManager.class);
         Preconditions.checkState(telephonyService != null, "Unable to access telephony service");
         mImei = telephonyService.getImei(0);
-        mMeid = telephonyService.getMeid(0);
+        String meid;
+        try {
+            meid = telephonyService.getMeid(0);
+        } catch (UnsupportedOperationException doesNotSupportCdma) {
+            // Instead of catching the exception, we could check for FEATURE_TELEPHONY_CDMA.
+            // However that runs the risk of changing a device's existing ESID if on these devices
+            // telephonyService.getMeid() actually returns non-null even when the device does not
+            // declare FEATURE_TELEPHONY_CDMA.
+            meid = null;
+        }
+        mMeid = meid;
         mSerialNumber = Build.getSerial();
         WifiManager wifiManager = context.getSystemService(WifiManager.class);
         Preconditions.checkState(wifiManager != null, "Unable to access WiFi service");
diff --git a/services/fakes/Android.bp b/services/fakes/Android.bp
new file mode 100644
index 0000000..148054b
--- /dev/null
+++ b/services/fakes/Android.bp
@@ -0,0 +1,20 @@
+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"],
+}
+
+// NOTE: These "fake" services are intended for use under the Ravenwood
+// deviceless test environment, and should *not* be included in the build
+// artifacts for physical devices, as they already supply "real" services
+filegroup {
+    name: "services.fakes-sources",
+    srcs: [
+        "java/**/*.java",
+    ],
+    path: "java",
+    visibility: ["//frameworks/base"],
+}
diff --git a/services/fakes/java/com/android/server/FakeClipboardService.java b/services/fakes/java/com/android/server/FakeClipboardService.java
new file mode 100644
index 0000000..0101621
--- /dev/null
+++ b/services/fakes/java/com/android/server/FakeClipboardService.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.Context;
+import android.content.IClipboard;
+import android.content.IOnPrimaryClipChangedListener;
+import android.os.PermissionEnforcer;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.UserHandle;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Fake implementation of {@code ClipboardManager} since the real implementation is tightly
+ * coupled with many other internal services.
+ */
+public class FakeClipboardService extends IClipboard.Stub {
+    private final RemoteCallbackList<IOnPrimaryClipChangedListener> mListeners =
+            new RemoteCallbackList<>();
+
+    private ClipData mPrimaryClip;
+    private String mPrimaryClipSource;
+
+    public FakeClipboardService(Context context) {
+        super(PermissionEnforcer.fromContext(context));
+    }
+
+    public static class Lifecycle extends SystemService {
+        private FakeClipboardService mService;
+
+        public Lifecycle(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            mService = new FakeClipboardService(getContext());
+            publishBinderService(Context.CLIPBOARD_SERVICE, mService);
+        }
+    }
+
+    private static void checkArguments(int userId, int deviceId) {
+        Preconditions.checkArgument(userId == UserHandle.USER_SYSTEM,
+                "Fake only supports USER_SYSTEM user");
+        Preconditions.checkArgument(deviceId == Context.DEVICE_ID_DEFAULT,
+                "Fake only supports DEVICE_ID_DEFAULT device");
+    }
+
+    private void dispatchPrimaryClipChanged() {
+        mListeners.broadcast((listener) -> {
+            try {
+                listener.dispatchPrimaryClipChanged();
+            } catch (RemoteException ignored) {
+            }
+        });
+    }
+
+    @Override
+    public void setPrimaryClip(ClipData clip, String callingPackage, String attributionTag,
+            int userId, int deviceId) {
+        checkArguments(userId, deviceId);
+        mPrimaryClip = clip;
+        mPrimaryClipSource = callingPackage;
+        dispatchPrimaryClipChanged();
+    }
+
+    @Override
+    @android.annotation.EnforcePermission(android.Manifest.permission.SET_CLIP_SOURCE)
+    public void setPrimaryClipAsPackage(ClipData clip, String callingPackage, String attributionTag,
+            int userId, int deviceId, String sourcePackage) {
+        setPrimaryClipAsPackage_enforcePermission();
+        checkArguments(userId, deviceId);
+        mPrimaryClip = clip;
+        mPrimaryClipSource = sourcePackage;
+        dispatchPrimaryClipChanged();
+    }
+
+    @Override
+    public void clearPrimaryClip(String callingPackage, String attributionTag, int userId,
+            int deviceId) {
+        checkArguments(userId, deviceId);
+        mPrimaryClip = null;
+        mPrimaryClipSource = null;
+        dispatchPrimaryClipChanged();
+    }
+
+    @Override
+    public ClipData getPrimaryClip(String pkg, String attributionTag, int userId, int deviceId) {
+        checkArguments(userId, deviceId);
+        return mPrimaryClip;
+    }
+
+    @Override
+    public ClipDescription getPrimaryClipDescription(String callingPackage, String attributionTag,
+            int userId, int deviceId) {
+        checkArguments(userId, deviceId);
+        return (mPrimaryClip != null) ? mPrimaryClip.getDescription() : null;
+    }
+
+    @Override
+    public boolean hasPrimaryClip(String callingPackage, String attributionTag, int userId,
+            int deviceId) {
+        checkArguments(userId, deviceId);
+        return mPrimaryClip != null;
+    }
+
+    @Override
+    public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener,
+            String callingPackage, String attributionTag, int userId, int deviceId) {
+        checkArguments(userId, deviceId);
+        mListeners.register(listener);
+    }
+
+    @Override
+    public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener,
+            String callingPackage, String attributionTag, int userId, int deviceId) {
+        checkArguments(userId, deviceId);
+        mListeners.unregister(listener);
+    }
+
+    @Override
+    public boolean hasClipboardText(String callingPackage, String attributionTag, int userId,
+            int deviceId) {
+        checkArguments(userId, deviceId);
+        return (mPrimaryClip != null) && (mPrimaryClip.getItemCount() > 0)
+                && (mPrimaryClip.getItemAt(0).getText() != null);
+    }
+
+    @Override
+    @android.annotation.EnforcePermission(android.Manifest.permission.SET_CLIP_SOURCE)
+    public String getPrimaryClipSource(String callingPackage, String attributionTag, int userId,
+            int deviceId) {
+        getPrimaryClipSource_enforcePermission();
+        checkArguments(userId, deviceId);
+        return mPrimaryClipSource;
+    }
+
+    @Override
+    public boolean areClipboardAccessNotificationsEnabledForUser(int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setClipboardAccessNotificationsEnabledForUser(boolean enable, int userId) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/services/fakes/java/com/android/server/example/BlueManagerService.java b/services/fakes/java/com/android/server/example/BlueManagerService.java
new file mode 100644
index 0000000..8e3c8d7
--- /dev/null
+++ b/services/fakes/java/com/android/server/example/BlueManagerService.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.example;
+
+import android.content.Context;
+import android.os.Binder;
+import android.ravenwood.example.BlueManager;
+
+import com.android.server.SystemService;
+
+public class BlueManagerService extends Binder {
+    public static class Lifecycle extends SystemService {
+        private BlueManagerService mService;
+
+        public Lifecycle(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            mService = new BlueManagerService();
+            publishBinderService(BlueManager.SERVICE_NAME, mService);
+        }
+    }
+
+    @Override
+    public String getInterfaceDescriptor() {
+        return "blue";
+    }
+}
diff --git a/services/fakes/java/com/android/server/example/RedManagerService.java b/services/fakes/java/com/android/server/example/RedManagerService.java
new file mode 100644
index 0000000..e0be733
--- /dev/null
+++ b/services/fakes/java/com/android/server/example/RedManagerService.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.example;
+
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.ravenwood.example.BlueManager;
+import android.ravenwood.example.RedManager;
+
+import com.android.server.SystemService;
+
+import java.util.List;
+
+public class RedManagerService extends Binder {
+    private IBinder mBlueService;
+
+    public static class Lifecycle extends SystemService {
+        private RedManagerService mService;
+
+        public Lifecycle(Context context) {
+            super(context, List.of(BlueManager.class));
+        }
+
+        @Override
+        public void onStart() {
+            mService = new RedManagerService();
+            publishBinderService(RedManager.SERVICE_NAME, mService);
+        }
+
+        @Override
+        public void onBootPhase(int phase) {
+            if (phase == PHASE_SYSTEM_SERVICES_READY) {
+                mService.mBlueService = getBinderService(BlueManager.SERVICE_NAME);
+            }
+        }
+    }
+
+    @Override
+    public String getInterfaceDescriptor() {
+        try {
+            // Obtain the answer from dependency, but then augment it to prove that the answer
+            // was channeled through us
+            return mBlueService.getInterfaceDescriptor() + "+red";
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e19f08c..9d95c5b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -2774,9 +2774,12 @@
         t.traceEnd();
 
         // OnDevicePersonalizationSystemService
-        t.traceBegin("StartOnDevicePersonalizationSystemService");
-        mSystemServiceManager.startService(ON_DEVICE_PERSONALIZATION_SYSTEM_SERVICE_CLASS);
-        t.traceEnd();
+        if (!com.android.server.flags.Flags.enableOdpFeatureGuard()
+                || SystemProperties.getBoolean("ro.system_settings.service.odp_enabled", true)) {
+            t.traceBegin("StartOnDevicePersonalizationSystemService");
+            mSystemServiceManager.startService(ON_DEVICE_PERSONALIZATION_SYSTEM_SERVICE_CLASS);
+            t.traceEnd();
+        }
 
         // Profiling
         if (android.server.Flags.telemetryApisService()) {
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
index 4b086b3..67df67f 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
@@ -227,25 +227,59 @@
             if (isRequestedBySystemPackage) {
                 return@forEach
             }
-            val oldFlags = getPermissionFlags(appId, userId, permissionName)
-            var newFlags = oldFlags andInv PermissionFlags.UPGRADE_EXEMPT
-            val isExempt = newFlags.hasAnyBit(PermissionFlags.MASK_EXEMPT)
-            newFlags =
-                if (permission.isHardRestricted && !isExempt) {
-                    newFlags or PermissionFlags.RESTRICTION_REVOKED
-                } else {
-                    newFlags andInv PermissionFlags.RESTRICTION_REVOKED
-                }
-            newFlags =
-                if (permission.isSoftRestricted && !isExempt) {
-                    newFlags or PermissionFlags.SOFT_RESTRICTED
-                } else {
-                    newFlags andInv PermissionFlags.SOFT_RESTRICTED
-                }
-            setPermissionFlags(appId, userId, permissionName, newFlags)
+            updatePermissionExemptFlags(
+                appId,
+                userId,
+                permission,
+                PermissionFlags.UPGRADE_EXEMPT,
+                0
+            )
         }
     }
 
+    fun MutateStateScope.updatePermissionExemptFlags(
+        appId: Int,
+        userId: Int,
+        permission: Permission,
+        exemptFlagMask: Int,
+        exemptFlagValues: Int
+    ) {
+        val permissionName = permission.name
+        val oldFlags = getPermissionFlags(appId, userId, permissionName)
+        var newFlags = (oldFlags andInv exemptFlagMask) or (exemptFlagValues and exemptFlagMask)
+        if (oldFlags == newFlags) {
+            return
+        }
+        val isExempt = newFlags.hasAnyBit(PermissionFlags.MASK_EXEMPT)
+        if (permission.isHardRestricted && !isExempt) {
+            newFlags = newFlags or PermissionFlags.RESTRICTION_REVOKED
+            // If the permission was policy fixed as granted but it is no longer on any of the
+            // allowlists we need to clear the policy fixed flag as allowlisting trumps policy i.e.
+            // policy cannot grant a non grantable permission.
+            if (PermissionFlags.isPermissionGranted(oldFlags)) {
+                newFlags = newFlags andInv PermissionFlags.POLICY_FIXED
+            }
+        } else {
+            newFlags = newFlags andInv PermissionFlags.RESTRICTION_REVOKED
+        }
+        newFlags =
+            if (
+                permission.isSoftRestricted && !isExempt &&
+                    !anyPackageInAppId(appId) {
+                        permissionName in it.androidPackage!!.requestedPermissions &&
+                            isSoftRestrictedPermissionExemptForPackage(it, permissionName)
+                    }
+            ) {
+                newFlags or PermissionFlags.SOFT_RESTRICTED
+            } else {
+                newFlags andInv PermissionFlags.SOFT_RESTRICTED
+            }
+        if (oldFlags == newFlags) {
+            return
+        }
+        setPermissionFlags(appId, userId, permissionName, newFlags)
+    }
+
     override fun MutateStateScope.onPackageUninstalled(
         packageName: String,
         appId: Int,
@@ -1118,7 +1152,12 @@
                     newFlags andInv PermissionFlags.RESTRICTION_REVOKED
                 }
             newFlags =
-                if (permission.isSoftRestricted && !isExempt) {
+                if (
+                    permission.isSoftRestricted && !isExempt &&
+                        !requestingPackageStates.anyIndexed { _, it ->
+                            isSoftRestrictedPermissionExemptForPackage(it, permissionName)
+                        }
+                ) {
                     newFlags or PermissionFlags.SOFT_RESTRICTED
                 } else {
                     newFlags andInv PermissionFlags.SOFT_RESTRICTED
@@ -1398,6 +1437,17 @@
         }
     }
 
+    // See also SoftRestrictedPermissionPolicy.mayGrantPermission()
+    private fun isSoftRestrictedPermissionExemptForPackage(
+        packageState: PackageState,
+        permissionName: String
+    ): Boolean =
+        when (permissionName) {
+            Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE ->
+                packageState.androidPackage!!.targetSdkVersion >= Build.VERSION_CODES.Q
+            else -> false
+        }
+
     private inline fun MutateStateScope.anyPackageInAppId(
         appId: Int,
         state: AccessState = newState,
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt
index b9d89c2..c5c921d 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt
@@ -346,8 +346,18 @@
         return flags.hasBits(RUNTIME_GRANTED)
     }
 
-    fun isAppOpGranted(flags: Int): Boolean =
-        isPermissionGranted(flags) && !flags.hasBits(APP_OP_REVOKED)
+    fun isAppOpGranted(flags: Int): Boolean {
+        if (!isPermissionGranted(flags)) {
+            return false
+        }
+        if (flags.hasAnyBit(MASK_RESTRICTED)) {
+            return false
+        }
+        if (flags.hasBits(APP_OP_REVOKED)) {
+            return false
+        }
+        return true
+    }
 
     fun toApiFlags(flags: Int): Int {
         var apiFlags = 0
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index 0704c8f..1f65463 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -88,7 +88,6 @@
 import com.android.server.pm.PackageManagerLocal
 import com.android.server.pm.UserManagerInternal
 import com.android.server.pm.UserManagerService
-import com.android.server.pm.parsing.pkg.AndroidPackageUtils
 import com.android.server.pm.permission.LegacyPermission
 import com.android.server.pm.permission.LegacyPermissionSettings
 import com.android.server.pm.permission.LegacyPermissionState
@@ -97,7 +96,6 @@
 import com.android.server.pm.permission.PermissionManagerServiceInternal
 import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageState
-import com.android.server.policy.SoftRestrictedPermissionPolicy
 import java.io.FileDescriptor
 import java.io.PrintWriter
 import java.util.concurrent.CompletableFuture
@@ -1006,25 +1004,14 @@
         }
 
         if (isGranted && oldFlags.hasBits(PermissionFlags.SOFT_RESTRICTED)) {
-            // TODO: Refactor SoftRestrictedPermissionPolicy.
-            val softRestrictedPermissionPolicy =
-                SoftRestrictedPermissionPolicy.forPermission(
-                    context,
-                    AndroidPackageUtils.generateAppInfoWithoutState(androidPackage),
-                    androidPackage,
-                    UserHandle.of(userId),
-                    permissionName
+            if (reportError) {
+                Slog.e(
+                    LOG_TAG,
+                    "$methodName: Cannot grant soft-restricted non-exempt permission" +
+                        " $permissionName to package $packageName"
                 )
-            if (!softRestrictedPermissionPolicy.mayGrantPermission()) {
-                if (reportError) {
-                    Slog.e(
-                        LOG_TAG,
-                        "$methodName: Cannot grant soft-restricted non-exempt permission" +
-                            " $permissionName to package $packageName"
-                    )
-                }
-                return
             }
+            return
         }
 
         val newFlags = PermissionFlags.updateRuntimePermissionGranted(oldFlags, isGranted)
@@ -1135,25 +1122,23 @@
             return emptyMap()
         }
 
-        val permissionFlagsMap =
-            service.getState {
+        service.getState {
+            val permissionFlags =
                 if (deviceId == VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT) {
                     with(policy) { getAllPermissionFlags(packageState.appId, userId) }
                 } else {
                     with(devicePolicy) {
                         getAllPermissionFlags(packageState.appId, deviceId, userId)
                     }
-                }
+                } ?: return emptyMap()
+            val permissionStates = ArrayMap<String, PermissionState>()
+            permissionFlags.forEachIndexed { _, permissionName, flags ->
+                val granted = isPermissionGranted(packageState, userId, permissionName, deviceId)
+                val apiFlags = PermissionFlags.toApiFlags(flags)
+                permissionStates[permissionName] = PermissionState(granted, apiFlags)
             }
-                ?: return emptyMap()
-
-        val permissionStates = ArrayMap<String, PermissionState>()
-        permissionFlagsMap.forEachIndexed { _, permissionName, flags ->
-            val granted = PermissionFlags.isPermissionGranted(flags)
-            val apiFlags = PermissionFlags.toApiFlags(flags)
-            permissionStates[permissionName] = PermissionState(granted, apiFlags)
+            return permissionStates
         }
-        return permissionStates
     }
 
     override fun isPermissionRevokedByPolicy(
@@ -1852,10 +1837,19 @@
         allowlistedFlags: Int,
         userId: Int
     ) {
+        var exemptMask = 0
+        if (allowlistedFlags.hasBits(PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM)) {
+            exemptMask = exemptMask or PermissionFlags.SYSTEM_EXEMPT
+        }
+        if (allowlistedFlags.hasBits(PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE)) {
+            exemptMask = exemptMask or PermissionFlags.UPGRADE_EXEMPT
+        }
+        if (allowlistedFlags.hasBits(PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) {
+            exemptMask = exemptMask or PermissionFlags.INSTALLER_EXEMPT
+        }
+
         service.mutateState {
             with(policy) {
-                val permissionsFlags = getUidPermissionFlags(appId, userId) ?: return@mutateState
-
                 val permissions = getPermissions()
                 androidPackage.requestedPermissions.forEachIndexed { _, requestedPermission ->
                     val permission = permissions[requestedPermission]
@@ -1863,81 +1857,8 @@
                         return@forEachIndexed
                     }
 
-                    val oldFlags = permissionsFlags[requestedPermission] ?: 0
-                    val wasGranted = PermissionFlags.isPermissionGranted(oldFlags)
-
-                    var newFlags = oldFlags
-                    var mask = 0
-                    var allowlistFlagsCopy = allowlistedFlags
-                    while (allowlistFlagsCopy != 0) {
-                        val flag = 1 shl allowlistFlagsCopy.countTrailingZeroBits()
-                        allowlistFlagsCopy = allowlistFlagsCopy and flag.inv()
-                        when (flag) {
-                            PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM -> {
-                                mask = mask or PermissionFlags.SYSTEM_EXEMPT
-                                newFlags =
-                                    if (permissionNames.contains(requestedPermission)) {
-                                        newFlags or PermissionFlags.SYSTEM_EXEMPT
-                                    } else {
-                                        newFlags andInv PermissionFlags.SYSTEM_EXEMPT
-                                    }
-                            }
-                            PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE -> {
-                                mask = mask or PermissionFlags.UPGRADE_EXEMPT
-                                newFlags =
-                                    if (permissionNames.contains(requestedPermission)) {
-                                        newFlags or PermissionFlags.UPGRADE_EXEMPT
-                                    } else {
-                                        newFlags andInv PermissionFlags.UPGRADE_EXEMPT
-                                    }
-                            }
-                            PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER -> {
-                                mask = mask or PermissionFlags.INSTALLER_EXEMPT
-                                newFlags =
-                                    if (permissionNames.contains(requestedPermission)) {
-                                        newFlags or PermissionFlags.INSTALLER_EXEMPT
-                                    } else {
-                                        newFlags andInv PermissionFlags.INSTALLER_EXEMPT
-                                    }
-                            }
-                        }
-                    }
-
-                    if (oldFlags == newFlags) {
-                        return@forEachIndexed
-                    }
-
-                    val isExempt = newFlags.hasAnyBit(PermissionFlags.MASK_EXEMPT)
-
-                    // If the permission is policy fixed as granted but it is no longer
-                    // on any of the allowlists we need to clear the policy fixed flag
-                    // as allowlisting trumps policy i.e. policy cannot grant a non
-                    // grantable permission.
-                    if (oldFlags.hasBits(PermissionFlags.POLICY_FIXED)) {
-                        if (!isExempt && wasGranted) {
-                            mask = mask or PermissionFlags.POLICY_FIXED
-                            newFlags = newFlags andInv PermissionFlags.POLICY_FIXED
-                        }
-                    }
-
-                    newFlags =
-                        if (permission.isHardRestricted && !isExempt) {
-                            newFlags or PermissionFlags.RESTRICTION_REVOKED
-                        } else {
-                            newFlags andInv PermissionFlags.RESTRICTION_REVOKED
-                        }
-                    newFlags =
-                        if (permission.isSoftRestricted && !isExempt) {
-                            newFlags or PermissionFlags.SOFT_RESTRICTED
-                        } else {
-                            newFlags andInv PermissionFlags.SOFT_RESTRICTED
-                        }
-                    mask =
-                        mask or
-                            PermissionFlags.RESTRICTION_REVOKED or
-                            PermissionFlags.SOFT_RESTRICTED
-
-                    updatePermissionFlags(appId, userId, requestedPermission, mask, newFlags)
+                    var exemptFlags = if (requestedPermission in permissionNames) exemptMask else 0
+                    updatePermissionExemptFlags(appId, userId, permission, exemptMask, exemptFlags)
                 }
             }
         }
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
index 1c71a62..1d225ba 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
@@ -30,7 +30,10 @@
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME_IMPLICIT;
 
 import static org.junit.Assert.assertThrows;
-import static org.mockito.Mockito.any;
+import static org.mockito.AdditionalMatchers.and;
+import static org.mockito.AdditionalMatchers.not;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.notNull;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
@@ -40,6 +43,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.view.Display;
+import android.view.inputmethod.ImeTracker;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
@@ -56,7 +60,7 @@
  * Test the behavior of {@link DefaultImeVisibilityApplier} when performing or applying the IME
  * visibility state.
  *
- * Build/Install/Run:
+ * <p>Build/Install/Run:
  * atest FrameworksInputMethodSystemServerTests:DefaultImeVisibilityApplierTest
  */
 @RunWith(AndroidJUnit4.class)
@@ -75,7 +79,8 @@
     public void testPerformShowIme() throws Exception {
         synchronized (ImfLock.class) {
             mVisibilityApplier.performShowIme(new Binder() /* showInputToken */,
-                    null /* statsToken */, 0 /* showFlags */, null, SHOW_SOFT_INPUT);
+                    ImeTracker.Token.empty(), 0 /* showFlags */, null /* resultReceiver */,
+                    SHOW_SOFT_INPUT);
         }
         verifyShowSoftInput(false, true, 0 /* showFlags */);
     }
@@ -84,46 +89,66 @@
     public void testPerformHideIme() throws Exception {
         synchronized (ImfLock.class) {
             mVisibilityApplier.performHideIme(new Binder() /* hideInputToken */,
-                    null /* statsToken */, null, HIDE_SOFT_INPUT);
+                    ImeTracker.Token.empty(), null /* resultReceiver */, HIDE_SOFT_INPUT);
         }
         verifyHideSoftInput(false, true);
     }
 
     @Test
     public void testApplyImeVisibility_throwForInvalidState() {
-        assertThrows(IllegalArgumentException.class,
-                () -> mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_INVALID));
+        assertThrows(IllegalArgumentException.class, () -> {
+            synchronized (ImfLock.class) {
+                mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
+                        STATE_INVALID);
+            }
+        });
     }
 
     @Test
     public void testApplyImeVisibility_showIme() {
-        mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_SHOW_IME);
-        verify(mMockWindowManagerInternal).showImePostLayout(eq(mWindowToken), any());
+        final var statsToken = ImeTracker.Token.empty();
+        synchronized (ImfLock.class) {
+            mVisibilityApplier.applyImeVisibility(mWindowToken, statsToken, STATE_SHOW_IME);
+        }
+        verify(mMockWindowManagerInternal).showImePostLayout(eq(mWindowToken), eq(statsToken));
     }
 
     @Test
     public void testApplyImeVisibility_hideIme() {
-        mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_HIDE_IME);
-        verify(mMockWindowManagerInternal).hideIme(eq(mWindowToken), anyInt(), any());
+        final var statsToken = ImeTracker.Token.empty();
+        synchronized (ImfLock.class) {
+            mVisibilityApplier.applyImeVisibility(mWindowToken, statsToken, STATE_HIDE_IME);
+        }
+        verify(mMockWindowManagerInternal).hideIme(eq(mWindowToken), anyInt() /* displayId */,
+                eq(statsToken));
     }
 
     @Test
     public void testApplyImeVisibility_hideImeExplicit() throws Exception {
         mInputMethodManagerService.mImeWindowVis = IME_ACTIVE;
-        mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_HIDE_IME_EXPLICIT);
+        synchronized (ImfLock.class) {
+            mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
+                    STATE_HIDE_IME_EXPLICIT);
+        }
         verifyHideSoftInput(true, true);
     }
 
     @Test
     public void testApplyImeVisibility_hideNotAlways() throws Exception {
         mInputMethodManagerService.mImeWindowVis = IME_ACTIVE;
-        mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_HIDE_IME_NOT_ALWAYS);
+        synchronized (ImfLock.class) {
+            mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
+                    STATE_HIDE_IME_NOT_ALWAYS);
+        }
         verifyHideSoftInput(true, true);
     }
 
     @Test
     public void testApplyImeVisibility_showImeImplicit() throws Exception {
-        mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_SHOW_IME_IMPLICIT);
+        synchronized (ImfLock.class) {
+            mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
+                    STATE_SHOW_IME_IMPLICIT);
+        }
         verifyShowSoftInput(true, true, 0 /* showFlags */);
     }
 
@@ -135,21 +160,21 @@
         mInputMethodManagerService.setAttachedClientForTesting(null);
         startInputOrWindowGainedFocus(mWindowToken, SOFT_INPUT_STATE_ALWAYS_VISIBLE);
 
+        final var statsToken = ImeTracker.Token.empty();
         synchronized (ImfLock.class) {
             final int displayIdToShowIme = mInputMethodManagerService.getDisplayIdToShowImeLocked();
             // Verify hideIme will apply the expected displayId when the default IME
             // visibility applier app STATE_HIDE_IME.
-            mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_HIDE_IME);
+            mVisibilityApplier.applyImeVisibility(mWindowToken, statsToken, STATE_HIDE_IME);
             verify(mInputMethodManagerService.mWindowManagerInternal).hideIme(
-                    eq(mWindowToken), eq(displayIdToShowIme), eq(null));
+                    eq(mWindowToken), eq(displayIdToShowIme), eq(statsToken));
         }
     }
 
     @Test
     public void testShowImeScreenshot() {
         synchronized (ImfLock.class) {
-            mVisibilityApplier.showImeScreenshot(mWindowToken, Display.DEFAULT_DISPLAY,
-                    null /* statsToken */);
+            mVisibilityApplier.showImeScreenshot(mWindowToken, Display.DEFAULT_DISPLAY);
         }
 
         verify(mMockImeTargetVisibilityPolicy).showImeScreenshot(eq(mWindowToken),
@@ -174,17 +199,20 @@
         synchronized (ImfLock.class) {
             // Simulate the system hides the IME when switching IME services in different users.
             // (e.g. unbinding the IME from the current user to the profile user)
+            final var statsToken = ImeTracker.Token.empty();
             final int displayIdToShowIme = mInputMethodManagerService.getDisplayIdToShowImeLocked();
-            mInputMethodManagerService.hideCurrentInputLocked(mWindowToken, null, 0, null,
+            mInputMethodManagerService.hideCurrentInputLocked(mWindowToken,
+                    statsToken, 0 /* flags */, null /* resultReceiver */,
                     HIDE_SWITCH_USER);
             mInputMethodManagerService.onUnbindCurrentMethodByReset();
 
             // Expects applyImeVisibility() -> hideIme() will be called to notify WM for syncing
             // the IME hidden state.
-            verify(mVisibilityApplier).applyImeVisibility(eq(mWindowToken), any(),
-                    eq(STATE_HIDE_IME));
+            // The unbind will cancel the previous stats token, and create a new one internally.
+            verify(mVisibilityApplier).applyImeVisibility(
+                    eq(mWindowToken), any(), eq(STATE_HIDE_IME));
             verify(mInputMethodManagerService.mWindowManagerInternal).hideIme(
-                    eq(mWindowToken), eq(displayIdToShowIme), eq(null));
+                    eq(mWindowToken), eq(displayIdToShowIme), and(not(eq(statsToken)), notNull()));
         }
     }
 
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
index fae5f86..a22cacb 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
@@ -39,9 +39,12 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.notNull;
+
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.view.inputmethod.ImeTracker;
 import android.view.inputmethod.InputMethodManager;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -58,7 +61,7 @@
  * Test the behavior of {@link ImeVisibilityStateComputer} and {@link ImeVisibilityApplier} when
  * requesting the IME visibility.
  *
- * Build/Install/Run:
+ * <p> Build/Install/Run:
  * atest FrameworksInputMethodSystemServerTests:ImeVisibilityStateComputerTest
  */
 @RunWith(AndroidJUnit4.class)
@@ -91,7 +94,8 @@
     @Test
     public void testRequestImeVisibility_showImplicit() {
         initImeTargetWindowState(mWindowToken);
-        boolean res = mComputer.onImeShowFlags(null, InputMethodManager.SHOW_IMPLICIT);
+        boolean res = mComputer.onImeShowFlags(ImeTracker.Token.empty(),
+                InputMethodManager.SHOW_IMPLICIT);
         mComputer.requestImeVisibility(mWindowToken, res);
 
         final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken);
@@ -106,7 +110,7 @@
     @Test
     public void testRequestImeVisibility_showExplicit() {
         initImeTargetWindowState(mWindowToken);
-        boolean res = mComputer.onImeShowFlags(null, 0 /* showFlags */);
+        boolean res = mComputer.onImeShowFlags(ImeTracker.Token.empty(), 0 /* showFlags */);
         mComputer.requestImeVisibility(mWindowToken, res);
 
         final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken);
@@ -125,7 +129,7 @@
     @Test
     public void testRequestImeVisibility_showExplicit_thenShowImplicit() {
         initImeTargetWindowState(mWindowToken);
-        mComputer.onImeShowFlags(null, 0 /* showFlags */);
+        mComputer.onImeShowFlags(ImeTracker.Token.empty(), 0 /* showFlags */);
         assertThat(mComputer.mRequestedShowExplicitly).isTrue();
 
         mComputer.onImeShowFlags(null, InputMethodManager.SHOW_IMPLICIT);
@@ -139,10 +143,10 @@
     @Test
     public void testRequestImeVisibility_showForced_thenShowExplicit() {
         initImeTargetWindowState(mWindowToken);
-        mComputer.onImeShowFlags(null, InputMethodManager.SHOW_FORCED);
+        mComputer.onImeShowFlags(ImeTracker.Token.empty(), InputMethodManager.SHOW_FORCED);
         assertThat(mComputer.mShowForced).isTrue();
 
-        mComputer.onImeShowFlags(null, 0 /* showFlags */);
+        mComputer.onImeShowFlags(ImeTracker.Token.empty(), 0 /* showFlags */);
         assertThat(mComputer.mShowForced).isTrue();
     }
 
@@ -152,7 +156,8 @@
         mComputer.getImePolicy().setA11yRequestNoSoftKeyboard(SHOW_MODE_HIDDEN);
 
         initImeTargetWindowState(mWindowToken);
-        boolean res = mComputer.onImeShowFlags(null, InputMethodManager.SHOW_IMPLICIT);
+        boolean res = mComputer.onImeShowFlags(ImeTracker.Token.empty(),
+                InputMethodManager.SHOW_IMPLICIT);
         mComputer.requestImeVisibility(mWindowToken, res);
 
         final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken);
@@ -170,7 +175,8 @@
         mComputer.getImePolicy().setImeHiddenByDisplayPolicy(true);
 
         initImeTargetWindowState(mWindowToken);
-        boolean res = mComputer.onImeShowFlags(null, InputMethodManager.SHOW_IMPLICIT);
+        boolean res = mComputer.onImeShowFlags(ImeTracker.Token.empty(),
+                InputMethodManager.SHOW_IMPLICIT);
         mComputer.requestImeVisibility(mWindowToken, res);
 
         final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken);
@@ -188,7 +194,8 @@
         mComputer.setInputShown(true);
 
         initImeTargetWindowState(mWindowToken);
-        assertThat(mComputer.canHideIme(null, InputMethodManager.HIDE_NOT_ALWAYS)).isTrue();
+        assertThat(mComputer.canHideIme(ImeTracker.Token.empty(),
+                InputMethodManager.HIDE_NOT_ALWAYS)).isTrue();
         mComputer.requestImeVisibility(mWindowToken, false);
 
         final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken);
@@ -281,7 +288,7 @@
         final ArgumentCaptor<ImeVisibilityResult> resultCaptor = ArgumentCaptor.forClass(
                 ImeVisibilityResult.class);
         verify(mInputMethodManagerService).onApplyImeVisibilityFromComputer(targetCaptor.capture(),
-                resultCaptor.capture());
+                notNull() /* statsToken */, resultCaptor.capture());
         final IBinder imeInputTarget = targetCaptor.getValue();
         final ImeVisibilityResult result = resultCaptor.getValue();
 
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
index a1be00a..f4d95af 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
@@ -27,6 +27,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.notNull;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -277,8 +278,9 @@
                     .setCurrentMethodVisible();
         }
         verify(mMockInputMethod, times(showSoftInput ? 1 : 0))
-                .showSoftInput(any(), any(),
-                        showFlags != NO_VERIFY_SHOW_FLAGS ? eq(showFlags) : anyInt(), any());
+                .showSoftInput(any() /* showInputToken */ , notNull() /* statsToken */,
+                        showFlags != NO_VERIFY_SHOW_FLAGS ? eq(showFlags) : anyInt() /* flags*/,
+                        any() /* resultReceiver */);
     }
 
     protected void verifyHideSoftInput(boolean setNotVisible, boolean hideSoftInput)
@@ -288,6 +290,7 @@
                     .setCurrentMethodNotVisible();
         }
         verify(mMockInputMethod, times(hideSoftInput ? 1 : 0))
-                .hideSoftInput(any(), any(), anyInt(), any());
+                .hideSoftInput(any() /* hideInputToken */, notNull() /* statsToken */,
+                        anyInt() /* flags */, any() /* resultReceiver */);
     }
 }
diff --git a/services/tests/PackageManagerServiceTests/preverifieddomains/Android.bp b/services/tests/PackageManagerServiceTests/preverifieddomains/Android.bp
new file mode 100644
index 0000000..39ef501
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/preverifieddomains/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_team: "trendy_team_framework_android_packages",
+    // 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"],
+}
+
+android_test {
+    name: "PreVerifiedDomainsTests",
+    srcs: [
+        "src/**/*.kt",
+    ],
+    static_libs: [
+        "compatibility-device-util-axt",
+        "androidx.test.runner",
+        "truth",
+    ],
+    platform_apis: true,
+    certificate: "platform",
+    test_suites: ["device-tests"],
+}
diff --git a/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidManifest.xml b/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidManifest.xml
new file mode 100644
index 0000000..ad731fc
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="com.android.server.pm.test.preverifieddomains">
+
+    <application android:label="PreVerified Domains Tests">
+        <activity
+            android:name="com.android.server.pm.test.preverifieddomains.FakeInstantAppInstallerActivity"
+            android:enabled="true"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.INSTALL_INSTANT_APP_PACKAGE_TEST" />
+                <category android:name="android.intent.category.DEFAULT"/>
+                <data android:scheme="file"/>
+                <data android:mimeType="application/vnd.android.package-archive"/>
+            </intent-filter>
+        </activity>
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.server.pm.test.preverifieddomains"
+                     android:label="Package Manager Service Tests for pre-verified domains">
+    </instrumentation>
+
+</manifest>
+
diff --git a/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidTest.xml b/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidTest.xml
new file mode 100644
index 0000000..45e193b
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<configuration description="Runs Package Manager Service Pre-Verified Domains Tests.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-instrumentation" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="PreVerifiedDomainsTests.apk" />
+    </target_preparer>
+
+    <option name="test-tag" value="PreVerifiedDomainsTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="com.android.server.pm.test.preverifieddomains" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false" />
+    </test>
+</configuration>
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/GoneSceneModule.kt b/services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/FakeInstantAppInstallerActivity.kt
similarity index 74%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/GoneSceneModule.kt
copy to services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/FakeInstantAppInstallerActivity.kt
index 5cc3b75d..d330490 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/GoneSceneModule.kt
+++ b/services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/FakeInstantAppInstallerActivity.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,9 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.server.pm.test.preverifieddomains
 
-package com.android.systemui.scene
+import android.app.Activity
 
-import dagger.Module
-
-@Module interface GoneSceneModule
+class FakeInstantAppInstallerActivity : Activity()
diff --git a/services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/PreVerifiedDomainsTests.kt b/services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/PreVerifiedDomainsTests.kt
new file mode 100644
index 0000000..7043216
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/PreVerifiedDomainsTests.kt
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.pm.test.preverifieddomains
+
+import android.app.UiAutomation
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.Flags
+import android.content.pm.PackageInstaller
+import android.content.pm.PackageInstaller.SessionParams.MODE_FULL_INSTALL
+import android.content.pm.PackageManager
+import android.os.Build
+import android.platform.test.annotations.RequiresFlagsEnabled
+import android.platform.test.flag.junit.CheckFlagsRule
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
+import android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.compatibility.common.util.DeviceConfigStateManager
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.AfterClass
+import org.junit.Assert.assertThrows
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.BeforeClass
+import org.junit.Rule
+import org.junit.Test
+import org.junit.function.ThrowingRunnable
+import org.junit.runner.RunWith
+
+/**
+ * Pre-verified domains API tests. These tests require the device's default instant app
+ * installer to be disabled temporarily and is only able to run on ENG builds.
+ */
+@RunWith(AndroidJUnit4::class)
+class PreVerifiedDomainsTests {
+    companion object {
+        private const val PROPERTY_PRE_VERIFIED_DOMAINS_COUNT_LIMIT =
+                "pre_verified_domains_count_limit"
+        private const val PROPERTY_PRE_VERIFIED_DOMAIN_LENGTH_LIMIT =
+                "pre_verified_domain_length_limit"
+        private const val TEMP_COUNT_LIMIT = 10
+        private const val TEMP_LENGTH_LIMIT = 15
+        private val testDomains = setOf("com.foo", "com.bar")
+
+        private val uiAutomation: UiAutomation =
+                InstrumentationRegistry.getInstrumentation().getUiAutomation()
+        private lateinit var packageManager: PackageManager
+        private var defaultInstantAppInstaller: ComponentName? = null
+        private lateinit var fakeInstantAppInstaller: ComponentName
+
+        @JvmStatic
+        @BeforeClass
+        fun setupBeforeClass() {
+            val context = InstrumentationRegistry.getInstrumentation().getContext()
+            packageManager = context.packageManager
+            defaultInstantAppInstaller = packageManager.getInstantAppInstallerComponent()
+            fakeInstantAppInstaller = ComponentName(
+                    context.packageName,
+                    context.packageName + ".FakeInstantAppInstallerActivity")
+            // By disabling the original instant app installer, this test app becomes the instant
+            // app installer
+            uiAutomation.adoptShellPermissionIdentity()
+            try {
+                // Enable the fake instant app installer before disabling the default one
+                packageManager.setComponentEnabledSetting(
+                        fakeInstantAppInstaller,
+                        PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+                        PackageManager.DONT_KILL_APP
+                )
+                if (defaultInstantAppInstaller != null) {
+                    packageManager.setComponentEnabledSetting(
+                            defaultInstantAppInstaller!!,
+                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                            0
+                    )
+                }
+            } finally {
+                uiAutomation.dropShellPermissionIdentity()
+            }
+            assertThat(fakeInstantAppInstaller).isEqualTo(
+                    packageManager.getInstantAppInstallerComponent())
+        }
+
+        @JvmStatic
+        @AfterClass
+        fun restoreInstantAppInstaller() {
+            uiAutomation.adoptShellPermissionIdentity()
+            try {
+                // Enable the original instant app installer before disabling the temporary one, so
+                // there won't be a time when the device doesn't have a valid instant app installer
+                if (defaultInstantAppInstaller != null) {
+                    packageManager.setComponentEnabledSetting(
+                            defaultInstantAppInstaller!!,
+                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+                            0
+                    )
+                }
+                // Be careful not to let this test process killed, or the test will be considered
+                // as failed
+                packageManager.setComponentEnabledSetting(
+                        fakeInstantAppInstaller,
+                        PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                        PackageManager.DONT_KILL_APP
+                )
+            } finally {
+                uiAutomation.dropShellPermissionIdentity()
+            }
+        }
+    }
+
+    private lateinit var packageInstaller: PackageInstaller
+    private lateinit var context: Context
+    private lateinit var packageManager: PackageManager
+    private var mDefaultCountLimit: String? = null
+    private var mDefaultLengthLimit: String? = null
+
+    @JvmField
+    @Rule
+    val mCheckFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+
+    @Before
+    fun setUp() {
+        context = InstrumentationRegistry.getInstrumentation().getContext()
+        packageManager = context.packageManager
+        packageInstaller = packageManager.packageInstaller
+        mDefaultCountLimit = getLimitFromDeviceConfig(PROPERTY_PRE_VERIFIED_DOMAINS_COUNT_LIMIT)
+        mDefaultLengthLimit = getLimitFromDeviceConfig(PROPERTY_PRE_VERIFIED_DOMAIN_LENGTH_LIMIT)
+    }
+
+    @After
+    fun cleanUp() {
+        setLimitInDeviceConfig(PROPERTY_PRE_VERIFIED_DOMAINS_COUNT_LIMIT, mDefaultCountLimit)
+        setLimitInDeviceConfig(PROPERTY_PRE_VERIFIED_DOMAIN_LENGTH_LIMIT, mDefaultLengthLimit)
+    }
+
+    @RequiresFlagsEnabled(Flags.FLAG_SET_PRE_VERIFIED_DOMAINS)
+    @Test
+    fun testSetPreVerifiedDomainsExceedsCountLimit() {
+        // Temporarily change the count limit to a much smaller number so the test can exceed it
+        setLimitInDeviceConfig(
+                PROPERTY_PRE_VERIFIED_DOMAINS_COUNT_LIMIT,
+                TEMP_COUNT_LIMIT.toString()
+        )
+        val domains = mutableSetOf<String>()
+        for (i in 0 until(TEMP_COUNT_LIMIT + 1)) {
+            domains.add("domain$i")
+        }
+
+        uiAutomation.adoptShellPermissionIdentity(android.Manifest.permission.ACCESS_INSTANT_APPS)
+        try {
+            assertThrows(
+                    IllegalArgumentException::class.java,
+                    ThrowingRunnable {
+                        createSessionWithPreVerifiedDomains(domains)
+                    }
+            )
+        } finally {
+            uiAutomation.dropShellPermissionIdentity()
+        }
+    }
+
+    @RequiresFlagsEnabled(Flags.FLAG_SET_PRE_VERIFIED_DOMAINS)
+    @Test
+    fun testSetPreVerifiedDomainsExceedsLengthLimit() {
+        // Temporarily change the count limit to a much smaller number so the test can exceed it
+        setLimitInDeviceConfig(
+                PROPERTY_PRE_VERIFIED_DOMAIN_LENGTH_LIMIT,
+                TEMP_LENGTH_LIMIT.toString()
+        )
+        val invalidDomain = "a".repeat(TEMP_LENGTH_LIMIT + 1)
+
+        uiAutomation.adoptShellPermissionIdentity(android.Manifest.permission.ACCESS_INSTANT_APPS)
+        try {
+            assertThrows(
+                    "Pre-verified domain: [" +
+                            invalidDomain + " ] exceeds maximum length allowed: " +
+                            TEMP_LENGTH_LIMIT,
+                    IllegalArgumentException::class.java,
+                    ThrowingRunnable {
+                        createSessionWithPreVerifiedDomains(setOf(invalidDomain))
+                    }
+            )
+        } finally {
+            uiAutomation.dropShellPermissionIdentity()
+        }
+    }
+
+    @RequiresFlagsEnabled(Flags.FLAG_SET_PRE_VERIFIED_DOMAINS)
+    @Test
+    fun testSetAndGetPreVerifiedDomains() {
+        // Fake instant app installers can only work on ENG builds
+        assumeTrue("eng" == Build.TYPE)
+        var session: PackageInstaller.Session? = null
+        uiAutomation.adoptShellPermissionIdentity(android.Manifest.permission.ACCESS_INSTANT_APPS)
+        try {
+            val sessionId = createSessionWithPreVerifiedDomains(testDomains)
+            session = packageInstaller.openSession(sessionId)
+            assertThat(session.getPreVerifiedDomains()).isEqualTo(testDomains)
+        } finally {
+            uiAutomation.dropShellPermissionIdentity()
+            session?.abandon()
+        }
+    }
+
+    private fun createSessionWithPreVerifiedDomains(domains: Set<String>): Int {
+        val sessionParam = PackageInstaller.SessionParams(MODE_FULL_INSTALL)
+        val sessionId = packageInstaller.createSession(sessionParam)
+        val session = packageInstaller.openSession(sessionId)
+        try {
+            session.setPreVerifiedDomains(domains)
+        } catch (e: Exception) {
+            session.abandon()
+            throw e
+        }
+        return sessionId
+    }
+
+    private fun getLimitFromDeviceConfig(propertyName: String): String? {
+        val stateManager = DeviceConfigStateManager(
+                context,
+                NAMESPACE_PACKAGE_MANAGER_SERVICE,
+                propertyName
+        )
+        return stateManager.get()
+    }
+
+    private fun setLimitInDeviceConfig(propertyName: String, value: String?) {
+        val stateManager = DeviceConfigStateManager(
+                context,
+                NAMESPACE_PACKAGE_MANAGER_SERVICE,
+                propertyName
+        )
+        val currentValue = stateManager.get()
+        if (currentValue != value) {
+            // Only change the value if the current value is different
+            stateManager.set(value)
+        }
+    }
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index d4b57f1..96e9ca0 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -275,6 +275,7 @@
         AndroidPackage::isUpdatableSystem,
         AndroidPackage::getEmergencyInstaller,
         AndroidPackage::isAllowCrossUidActivitySwitchFromBelow,
+        PackageImpl::isAppMetadataFileInApk,
     )
 
     override fun extraParams() = listOf(
diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt
index cde46ab..96753b6 100644
--- a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt
+++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt
@@ -233,24 +233,6 @@
             .isEqualTo(expectedNewFlags)
     }
 
-    @Test
-    fun testOnPackageInstalled_restrictedPermissionsIsExempted_clearsRestrictionFlags() {
-        val oldFlags = PermissionFlags.SOFT_RESTRICTED or PermissionFlags.INSTALLER_EXEMPT
-        testOnPackageInstalled(
-            oldFlags,
-            permissionInfoFlags = PermissionInfo.FLAG_SOFT_RESTRICTED
-        ) {}
-        val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
-        val expectedNewFlags = PermissionFlags.INSTALLER_EXEMPT
-        assertWithMessage(
-            "After onPackageInstalled() is called for a non-system app that requests a runtime" +
-                " soft restricted permission that is exempted. The actual permission flags" +
-                " $actualFlags should match the expected flags $expectedNewFlags"
-        )
-            .that(actualFlags)
-            .isEqualTo(expectedNewFlags)
-    }
-
     private fun testOnPackageInstalled(
         oldFlags: Int,
         permissionInfoFlags: Int = 0,
diff --git a/services/tests/VpnTests/Android.bp b/services/tests/VpnTests/Android.bp
new file mode 100644
index 0000000..64a9a3b
--- /dev/null
+++ b/services/tests/VpnTests/Android.bp
@@ -0,0 +1,39 @@
+//########################################################################
+// Build FrameworksVpnTests package
+//########################################################################
+package {
+    default_team: "trendy_team_fwk_core_networking",
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "Android-Apache-2.0"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+    name: "FrameworksVpnTests",
+    srcs: [
+        "java/**/*.java",
+        "java/**/*.kt",
+    ],
+
+    defaults: ["framework-connectivity-test-defaults"],
+    test_suites: ["device-tests"],
+    static_libs: [
+        "androidx.test.rules",
+        "frameworks-base-testutils",
+        "framework-protos",
+        "mockito-target-minus-junit4",
+        "net-tests-utils",
+        "platform-test-annotations",
+        "services.core",
+        "cts-net-utils",
+        "service-connectivity-tiramisu-pre-jarjar",
+    ],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+        "android.test.mock",
+    ],
+}
diff --git a/services/tests/VpnTests/AndroidManifest.xml b/services/tests/VpnTests/AndroidManifest.xml
new file mode 100644
index 0000000..d884084
--- /dev/null
+++ b/services/tests/VpnTests/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.frameworks.tests.vpn">
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.frameworks.tests.vpn"
+        android:label="Frameworks VPN Tests" />
+</manifest>
\ No newline at end of file
diff --git a/services/tests/VpnTests/AndroidTest.xml b/services/tests/VpnTests/AndroidTest.xml
new file mode 100644
index 0000000..ebeeac7
--- /dev/null
+++ b/services/tests/VpnTests/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<configuration description="Runs VPN Tests.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="FrameworksVpnTests.apk" />
+    </target_preparer>
+
+    <option name="test-tag" value="FrameworksVpnTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.frameworks.tests.vpn" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/services/tests/VpnTests/OWNERS b/services/tests/VpnTests/OWNERS
new file mode 100644
index 0000000..45ea251
--- /dev/null
+++ b/services/tests/VpnTests/OWNERS
@@ -0,0 +1,2 @@
+set noparent
+file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking
\ No newline at end of file
diff --git a/services/tests/VpnTests/java/com/android/server/VpnManagerServiceTest.java b/services/tests/VpnTests/java/com/android/server/VpnManagerServiceTest.java
new file mode 100644
index 0000000..ecc70e3
--- /dev/null
+++ b/services/tests/VpnTests/java/com/android/server/VpnManagerServiceTest.java
@@ -0,0 +1,400 @@
+/*
+ * 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.server;
+
+import static com.android.testutils.ContextUtils.mockService;
+import static com.android.testutils.MiscAsserts.assertThrows;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.annotation.UserIdInt;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.INetd;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.INetworkManagementService;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.security.Credentials;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.net.VpnProfile;
+import com.android.server.connectivity.Vpn;
+import com.android.server.connectivity.VpnProfileStore;
+import com.android.server.net.LockdownVpnTracker;
+import com.android.testutils.HandlerUtils;
+
+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.nio.charset.StandardCharsets;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VpnManagerServiceTest extends VpnTestBase {
+    private static final String CONTEXT_ATTRIBUTION_TAG = "VPN_MANAGER";
+
+    private static final int TIMEOUT_MS = 2_000;
+
+    @Mock Context mContext;
+    @Mock Context mContextWithoutAttributionTag;
+    @Mock Context mSystemContext;
+    @Mock Context mUserAllContext;
+    private HandlerThread mHandlerThread;
+    @Mock private Vpn mVpn;
+    @Mock private INetworkManagementService mNms;
+    @Mock private ConnectivityManager mCm;
+    @Mock private UserManager mUserManager;
+    @Mock private INetd mNetd;
+    @Mock private PackageManager mPackageManager;
+    @Mock private VpnProfileStore mVpnProfileStore;
+    @Mock private LockdownVpnTracker mLockdownVpnTracker;
+
+    private VpnManagerServiceDependencies mDeps;
+    private VpnManagerService mService;
+    private BroadcastReceiver mUserPresentReceiver;
+    private BroadcastReceiver mIntentReceiver;
+    private final String mNotMyVpnPkg = "com.not.my.vpn";
+
+    class VpnManagerServiceDependencies extends VpnManagerService.Dependencies {
+        @Override
+        public HandlerThread makeHandlerThread() {
+            return mHandlerThread;
+        }
+
+        @Override
+        public INetworkManagementService getINetworkManagementService() {
+            return mNms;
+        }
+
+        @Override
+        public INetd getNetd() {
+            return mNetd;
+        }
+
+        @Override
+        public Vpn createVpn(Looper looper, Context context, INetworkManagementService nms,
+                INetd netd, @UserIdInt int userId) {
+            return mVpn;
+        }
+
+        @Override
+        public VpnProfileStore getVpnProfileStore() {
+            return mVpnProfileStore;
+        }
+
+        @Override
+        public LockdownVpnTracker createLockDownVpnTracker(Context context, Handler handler,
+                Vpn vpn, VpnProfile profile) {
+            return mLockdownVpnTracker;
+        }
+
+        @Override
+        public @UserIdInt int getMainUserId() {
+            return UserHandle.USER_SYSTEM;
+        }
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mHandlerThread = new HandlerThread("TestVpnManagerService");
+        mDeps = new VpnManagerServiceDependencies();
+
+        // The attribution tag is a dependency for IKE library to collect VPN metrics correctly
+        // and thus should not be changed without updating the IKE code.
+        doReturn(mContext)
+                .when(mContextWithoutAttributionTag)
+                .createAttributionContext(CONTEXT_ATTRIBUTION_TAG);
+
+        doReturn(mUserAllContext).when(mContext).createContextAsUser(UserHandle.ALL, 0);
+        doReturn(mSystemContext).when(mContext).createContextAsUser(UserHandle.SYSTEM, 0);
+        doReturn(mPackageManager).when(mContext).getPackageManager();
+        setMockedPackages(mPackageManager, sPackages);
+
+        mockService(mContext, ConnectivityManager.class, Context.CONNECTIVITY_SERVICE, mCm);
+        mockService(mContext, UserManager.class, Context.USER_SERVICE, mUserManager);
+        doReturn(SYSTEM_USER).when(mUserManager).getUserInfo(eq(SYSTEM_USER_ID));
+
+        mService = new VpnManagerService(mContextWithoutAttributionTag, mDeps);
+        mService.systemReady();
+
+        final ArgumentCaptor<BroadcastReceiver> intentReceiverCaptor =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+        final ArgumentCaptor<BroadcastReceiver> userPresentReceiverCaptor =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+        verify(mSystemContext).registerReceiver(
+                userPresentReceiverCaptor.capture(), any(), any(), any());
+        verify(mUserAllContext, times(2)).registerReceiver(
+                intentReceiverCaptor.capture(), any(), any(), any());
+        mUserPresentReceiver = userPresentReceiverCaptor.getValue();
+        mIntentReceiver = intentReceiverCaptor.getValue();
+
+        // Add user to create vpn in mVpn
+        onUserStarted(SYSTEM_USER_ID);
+        assertNotNull(mService.mVpns.get(SYSTEM_USER_ID));
+    }
+
+    @Test
+    public void testUpdateAppExclusionList() {
+        // Start vpn
+        mService.startVpnProfile(TEST_VPN_PKG);
+        verify(mVpn).startVpnProfile(eq(TEST_VPN_PKG));
+
+        // Remove package due to package replaced.
+        onPackageRemoved(PKGS[0], PKG_UIDS[0], true /* isReplacing */);
+        verify(mVpn, never()).refreshPlatformVpnAppExclusionList();
+
+        // Add package due to package replaced.
+        onPackageAdded(PKGS[0], PKG_UIDS[0], true /* isReplacing */);
+        verify(mVpn, never()).refreshPlatformVpnAppExclusionList();
+
+        // Remove package
+        onPackageRemoved(PKGS[0], PKG_UIDS[0], false /* isReplacing */);
+        verify(mVpn).refreshPlatformVpnAppExclusionList();
+
+        // Add the package back
+        onPackageAdded(PKGS[0], PKG_UIDS[0], false /* isReplacing */);
+        verify(mVpn, times(2)).refreshPlatformVpnAppExclusionList();
+    }
+
+    @Test
+    public void testStartVpnProfileFromDiffPackage() {
+        assertThrows(
+                SecurityException.class, () -> mService.startVpnProfile(mNotMyVpnPkg));
+    }
+
+    @Test
+    public void testStopVpnProfileFromDiffPackage() {
+        assertThrows(SecurityException.class, () -> mService.stopVpnProfile(mNotMyVpnPkg));
+    }
+
+    @Test
+    public void testGetProvisionedVpnProfileStateFromDiffPackage() {
+        assertThrows(SecurityException.class, () ->
+                mService.getProvisionedVpnProfileState(mNotMyVpnPkg));
+    }
+
+    @Test
+    public void testGetProvisionedVpnProfileState() {
+        mService.getProvisionedVpnProfileState(TEST_VPN_PKG);
+        verify(mVpn).getProvisionedVpnProfileState(TEST_VPN_PKG);
+    }
+
+    private Intent buildIntent(String action, String packageName, int userId, int uid,
+            boolean isReplacing) {
+        final Intent intent = new Intent(action);
+        intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+        intent.putExtra(Intent.EXTRA_UID, uid);
+        intent.putExtra(Intent.EXTRA_REPLACING, isReplacing);
+        if (packageName != null) {
+            intent.setData(Uri.fromParts("package" /* scheme */, packageName, null /* fragment */));
+        }
+
+        return intent;
+    }
+
+    private void sendIntent(Intent intent) {
+        sendIntent(mIntentReceiver, mContext, intent);
+    }
+
+    private void sendIntent(BroadcastReceiver receiver, Context context, Intent intent) {
+        final Handler h = mHandlerThread.getThreadHandler();
+
+        // Send in handler thread.
+        h.post(() -> receiver.onReceive(context, intent));
+        HandlerUtils.waitForIdle(mHandlerThread, TIMEOUT_MS);
+    }
+
+    private void onUserStarted(int userId) {
+        sendIntent(buildIntent(Intent.ACTION_USER_STARTED,
+                null /* packageName */, userId, -1 /* uid */, false /* isReplacing */));
+    }
+
+    private void onUserUnlocked(int userId) {
+        sendIntent(buildIntent(Intent.ACTION_USER_UNLOCKED,
+                null /* packageName */, userId, -1 /* uid */, false /* isReplacing */));
+    }
+
+    private void onUserStopped(int userId) {
+        sendIntent(buildIntent(Intent.ACTION_USER_STOPPED,
+                null /* packageName */, userId, -1 /* uid */, false /* isReplacing */));
+    }
+
+    private void onLockDownReset() {
+        sendIntent(buildIntent(LockdownVpnTracker.ACTION_LOCKDOWN_RESET, null /* packageName */,
+                UserHandle.USER_SYSTEM, -1 /* uid */, false /* isReplacing */));
+    }
+
+    private void onPackageAdded(String packageName, int userId, int uid, boolean isReplacing) {
+        sendIntent(buildIntent(Intent.ACTION_PACKAGE_ADDED, packageName, userId, uid, isReplacing));
+    }
+
+    private void onPackageAdded(String packageName, int uid, boolean isReplacing) {
+        onPackageAdded(packageName, UserHandle.USER_SYSTEM, uid, isReplacing);
+    }
+
+    private void onPackageRemoved(String packageName, int userId, int uid, boolean isReplacing) {
+        sendIntent(buildIntent(Intent.ACTION_PACKAGE_REMOVED, packageName, userId, uid,
+                isReplacing));
+    }
+
+    private void onPackageRemoved(String packageName, int uid, boolean isReplacing) {
+        onPackageRemoved(packageName, UserHandle.USER_SYSTEM, uid, isReplacing);
+    }
+
+    @Test
+    public void testReceiveIntentFromNonHandlerThread() {
+        assertThrows(IllegalStateException.class, () ->
+                mIntentReceiver.onReceive(mContext, buildIntent(Intent.ACTION_PACKAGE_REMOVED,
+                        PKGS[0], UserHandle.USER_SYSTEM, PKG_UIDS[0], true /* isReplacing */)));
+
+        assertThrows(IllegalStateException.class, () ->
+                mUserPresentReceiver.onReceive(mContext, new Intent(Intent.ACTION_USER_PRESENT)));
+    }
+
+    private void setupLockdownVpn(String packageName) {
+        final byte[] profileTag = packageName.getBytes(StandardCharsets.UTF_8);
+        doReturn(profileTag).when(mVpnProfileStore).get(Credentials.LOCKDOWN_VPN);
+    }
+
+    private void setupVpnProfile(String profileName) {
+        final VpnProfile profile = new VpnProfile(profileName);
+        profile.name = profileName;
+        profile.server = "192.0.2.1";
+        profile.dnsServers = "8.8.8.8";
+        profile.type = VpnProfile.TYPE_IPSEC_XAUTH_PSK;
+        final byte[] encodedProfile = profile.encode();
+        doReturn(encodedProfile).when(mVpnProfileStore).get(Credentials.VPN + profileName);
+    }
+
+    @Test
+    public void testUserPresent() {
+        // Verify that LockDownVpnTracker is not created.
+        verify(mLockdownVpnTracker, never()).init();
+
+        setupLockdownVpn(TEST_VPN_PKG);
+        setupVpnProfile(TEST_VPN_PKG);
+
+        // mUserPresentReceiver only registers ACTION_USER_PRESENT intent and does no verification
+        // on action, so an empty intent is enough.
+        sendIntent(mUserPresentReceiver, mSystemContext, new Intent());
+
+        verify(mLockdownVpnTracker).init();
+        verify(mSystemContext).unregisterReceiver(mUserPresentReceiver);
+        verify(mUserAllContext, never()).unregisterReceiver(any());
+    }
+
+    @Test
+    public void testUpdateLockdownVpn() {
+        setupLockdownVpn(TEST_VPN_PKG);
+        onUserUnlocked(SYSTEM_USER_ID);
+
+        // Will not create lockDownVpnTracker w/o valid profile configured in the keystore
+        verify(mLockdownVpnTracker, never()).init();
+
+        setupVpnProfile(TEST_VPN_PKG);
+
+        // Remove the user from mVpns
+        onUserStopped(SYSTEM_USER_ID);
+        onUserUnlocked(SYSTEM_USER_ID);
+        verify(mLockdownVpnTracker, never()).init();
+
+        // Add user back
+        onUserStarted(SYSTEM_USER_ID);
+        verify(mLockdownVpnTracker).init();
+
+        // Trigger another update. The existing LockDownVpnTracker should be shut down and
+        // initialize another one.
+        onUserUnlocked(SYSTEM_USER_ID);
+        verify(mLockdownVpnTracker).shutdown();
+        verify(mLockdownVpnTracker, times(2)).init();
+    }
+
+    @Test
+    public void testLockdownReset() {
+        // Init LockdownVpnTracker
+        setupLockdownVpn(TEST_VPN_PKG);
+        setupVpnProfile(TEST_VPN_PKG);
+        onUserUnlocked(SYSTEM_USER_ID);
+        verify(mLockdownVpnTracker).init();
+
+        onLockDownReset();
+        verify(mLockdownVpnTracker).reset();
+    }
+
+    @Test
+    public void testLockdownResetWhenLockdownVpnTrackerIsNotInit() {
+        setupLockdownVpn(TEST_VPN_PKG);
+        setupVpnProfile(TEST_VPN_PKG);
+
+        onLockDownReset();
+
+        // LockDownVpnTracker is not created. Lockdown reset will not take effect.
+        verify(mLockdownVpnTracker, never()).reset();
+    }
+
+    @Test
+    public void testIsVpnLockdownEnabled() {
+        // Vpn is created but the VPN lockdown is not enabled.
+        assertFalse(mService.isVpnLockdownEnabled(SYSTEM_USER_ID));
+
+        // Set lockdown for the SYSTEM_USER_ID VPN.
+        doReturn(true).when(mVpn).getLockdown();
+        assertTrue(mService.isVpnLockdownEnabled(SYSTEM_USER_ID));
+
+        // Even lockdown is enabled but no Vpn is created for SECONDARY_USER.
+        assertFalse(mService.isVpnLockdownEnabled(SECONDARY_USER.id));
+    }
+
+    @Test
+    public void testGetVpnLockdownAllowlist() {
+        doReturn(null).when(mVpn).getLockdownAllowlist();
+        assertNull(mService.getVpnLockdownAllowlist(SYSTEM_USER_ID));
+
+        final List<String> expected = List.of(PKGS);
+        doReturn(expected).when(mVpn).getLockdownAllowlist();
+        assertEquals(expected, mService.getVpnLockdownAllowlist(SYSTEM_USER_ID));
+
+        // Even lockdown is enabled but no Vpn is created for SECONDARY_USER.
+        assertNull(mService.getVpnLockdownAllowlist(SECONDARY_USER.id));
+    }
+}
diff --git a/services/tests/VpnTests/java/com/android/server/VpnTestBase.java b/services/tests/VpnTests/java/com/android/server/VpnTestBase.java
new file mode 100644
index 0000000..6113872
--- /dev/null
+++ b/services/tests/VpnTests/java/com/android/server/VpnTestBase.java
@@ -0,0 +1,97 @@
+/*
+ * 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.server;
+
+import static android.content.pm.UserInfo.FLAG_ADMIN;
+import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
+import static android.content.pm.UserInfo.FLAG_PRIMARY;
+import static android.content.pm.UserInfo.FLAG_RESTRICTED;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doAnswer;
+
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.os.Process;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/** Common variables or methods shared between VpnTest and VpnManagerServiceTest. */
+public class VpnTestBase {
+    protected static final String TEST_VPN_PKG = "com.testvpn.vpn";
+    /**
+     * Names and UIDs for some fake packages. Important points:
+     *  - UID is ordered increasing.
+     *  - One pair of packages have consecutive UIDs.
+     */
+    protected static final String[] PKGS = {"com.example", "org.example", "net.example", "web.vpn"};
+    protected static final int[] PKG_UIDS = {10066, 10077, 10078, 10400};
+    // Mock packages
+    protected static final Map<String, Integer> sPackages = new ArrayMap<>();
+    static {
+        for (int i = 0; i < PKGS.length; i++) {
+            sPackages.put(PKGS[i], PKG_UIDS[i]);
+        }
+        sPackages.put(TEST_VPN_PKG, Process.myUid());
+    }
+
+    // Mock users
+    protected static final int SYSTEM_USER_ID = 0;
+    protected static final UserInfo SYSTEM_USER = new UserInfo(0, "system", UserInfo.FLAG_PRIMARY);
+    protected static final UserInfo PRIMARY_USER = new UserInfo(27, "Primary",
+            FLAG_ADMIN | FLAG_PRIMARY);
+    protected static final UserInfo SECONDARY_USER = new UserInfo(15, "Secondary", FLAG_ADMIN);
+    protected static final UserInfo RESTRICTED_PROFILE_A = new UserInfo(40, "RestrictedA",
+            FLAG_RESTRICTED);
+    protected static final UserInfo RESTRICTED_PROFILE_B = new UserInfo(42, "RestrictedB",
+            FLAG_RESTRICTED);
+    protected static final UserInfo MANAGED_PROFILE_A = new UserInfo(45, "ManagedA",
+            FLAG_MANAGED_PROFILE);
+    static {
+        RESTRICTED_PROFILE_A.restrictedProfileParentId = PRIMARY_USER.id;
+        RESTRICTED_PROFILE_B.restrictedProfileParentId = SECONDARY_USER.id;
+        MANAGED_PROFILE_A.profileGroupId = PRIMARY_USER.id;
+    }
+
+    // Populate a fake packageName-to-UID mapping.
+    protected void setMockedPackages(PackageManager mockPm, final Map<String, Integer> packages) {
+        try {
+            doAnswer(invocation -> {
+                final String appName = (String) invocation.getArguments()[0];
+                final int userId = (int) invocation.getArguments()[1];
+
+                final Integer appId = packages.get(appName);
+                if (appId == null) {
+                    throw new PackageManager.NameNotFoundException(appName);
+                }
+
+                return UserHandle.getUid(userId, appId);
+            }).when(mockPm).getPackageUidAsUser(anyString(), anyInt());
+        } catch (Exception e) {
+        }
+    }
+
+    protected List<Integer> toList(int[] arr) {
+        return Arrays.stream(arr).boxed().collect(Collectors.toList());
+    }
+}
diff --git a/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
new file mode 100644
index 0000000..9115f95
--- /dev/null
+++ b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
@@ -0,0 +1,3293 @@
+/*
+ * 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 com.android.server.connectivity;
+
+import static android.Manifest.permission.BIND_VPN_SERVICE;
+import static android.Manifest.permission.CONTROL_VPN;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback;
+import static android.net.ConnectivityDiagnosticsManager.DataStallReport;
+import static android.net.ConnectivityManager.NetworkCallback;
+import static android.net.INetd.IF_STATE_DOWN;
+import static android.net.INetd.IF_STATE_UP;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.RouteInfo.RTN_UNREACHABLE;
+import static android.net.VpnManager.TYPE_VPN_PLATFORM;
+import static android.net.cts.util.IkeSessionTestUtils.CHILD_PARAMS;
+import static android.net.cts.util.IkeSessionTestUtils.TEST_IDENTITY;
+import static android.net.cts.util.IkeSessionTestUtils.TEST_KEEPALIVE_TIMEOUT_UNSET;
+import static android.net.cts.util.IkeSessionTestUtils.getTestIkeSessionParams;
+import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_MOBIKE;
+import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_AUTO;
+import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_NONE;
+import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_UDP;
+import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_AUTO;
+import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_IPV4;
+import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_IPV6;
+import static android.os.UserHandle.PER_USER_RANGE;
+import static android.telephony.CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL;
+import static android.telephony.CarrierConfigManager.KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT;
+import static android.telephony.CarrierConfigManager.KEY_PREFERRED_IKE_PROTOCOL_INT;
+
+import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
+import static com.android.server.connectivity.Vpn.AUTOMATIC_KEEPALIVE_DELAY_SECONDS;
+import static com.android.server.connectivity.Vpn.DEFAULT_LONG_LIVED_TCP_CONNS_EXPENSIVE_TIMEOUT_SEC;
+import static com.android.server.connectivity.Vpn.DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT;
+import static com.android.server.connectivity.Vpn.PREFERRED_IKE_PROTOCOL_AUTO;
+import static com.android.server.connectivity.Vpn.PREFERRED_IKE_PROTOCOL_IPV4_UDP;
+import static com.android.server.connectivity.Vpn.PREFERRED_IKE_PROTOCOL_IPV6_ESP;
+import static com.android.server.connectivity.Vpn.PREFERRED_IKE_PROTOCOL_IPV6_UDP;
+import static com.android.testutils.HandlerUtils.waitForIdleSerialExecutor;
+import static com.android.testutils.MiscAsserts.assertThrows;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.longThat;
+import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.AppOpsManager;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.net.ConnectivityDiagnosticsManager;
+import android.net.ConnectivityManager;
+import android.net.INetd;
+import android.net.Ikev2VpnProfile;
+import android.net.InetAddresses;
+import android.net.InterfaceConfigurationParcel;
+import android.net.IpPrefix;
+import android.net.IpSecConfig;
+import android.net.IpSecManager;
+import android.net.IpSecTransform;
+import android.net.IpSecTunnelInterfaceResponse;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkAgent;
+import android.net.NetworkAgentConfig;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo.DetailedState;
+import android.net.RouteInfo;
+import android.net.TelephonyNetworkSpecifier;
+import android.net.UidRangeParcel;
+import android.net.VpnManager;
+import android.net.VpnProfileState;
+import android.net.VpnService;
+import android.net.VpnTransportInfo;
+import android.net.ipsec.ike.ChildSessionCallback;
+import android.net.ipsec.ike.ChildSessionConfiguration;
+import android.net.ipsec.ike.IkeFqdnIdentification;
+import android.net.ipsec.ike.IkeSessionCallback;
+import android.net.ipsec.ike.IkeSessionConfiguration;
+import android.net.ipsec.ike.IkeSessionConnectionInfo;
+import android.net.ipsec.ike.IkeSessionParams;
+import android.net.ipsec.ike.IkeTrafficSelector;
+import android.net.ipsec.ike.IkeTunnelConnectionParams;
+import android.net.ipsec.ike.exceptions.IkeException;
+import android.net.ipsec.ike.exceptions.IkeNetworkLostException;
+import android.net.ipsec.ike.exceptions.IkeNonProtocolException;
+import android.net.ipsec.ike.exceptions.IkeProtocolException;
+import android.net.ipsec.ike.exceptions.IkeTimeoutException;
+import android.net.vcn.VcnTransportInfo;
+import android.net.wifi.WifiInfo;
+import android.os.Build.VERSION_CODES;
+import android.os.Bundle;
+import android.os.INetworkManagementService;
+import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
+import android.os.PowerWhitelistManager;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.test.TestLooper;
+import android.provider.Settings;
+import android.security.Credentials;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Pair;
+import android.util.Range;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.R;
+import com.android.internal.net.LegacyVpnInfo;
+import com.android.internal.net.VpnConfig;
+import com.android.internal.net.VpnProfile;
+import com.android.internal.util.HexDump;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.DeviceIdleInternal;
+import com.android.server.IpSecService;
+import com.android.server.VpnTestBase;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.AdditionalAnswers;
+import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Tests for {@link Vpn}.
+ *
+ * Build, install and run with:
+ *  runtest frameworks-net -c com.android.server.connectivity.VpnTest
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VpnTest extends VpnTestBase {
+    private static final String TAG = "VpnTest";
+
+    static final Network EGRESS_NETWORK = new Network(101);
+    static final String EGRESS_IFACE = "wlan0";
+    private static final String TEST_VPN_CLIENT = "2.4.6.8";
+    private static final String TEST_VPN_SERVER = "1.2.3.4";
+    private static final String TEST_VPN_IDENTITY = "identity";
+    private static final byte[] TEST_VPN_PSK = "psk".getBytes();
+
+    private static final int IP4_PREFIX_LEN = 32;
+    private static final int IP6_PREFIX_LEN = 64;
+    private static final int MIN_PORT = 0;
+    private static final int MAX_PORT = 65535;
+
+    private static final InetAddress TEST_VPN_CLIENT_IP =
+            InetAddresses.parseNumericAddress(TEST_VPN_CLIENT);
+    private static final InetAddress TEST_VPN_SERVER_IP =
+            InetAddresses.parseNumericAddress(TEST_VPN_SERVER);
+    private static final InetAddress TEST_VPN_CLIENT_IP_2 =
+            InetAddresses.parseNumericAddress("192.0.2.200");
+    private static final InetAddress TEST_VPN_SERVER_IP_2 =
+            InetAddresses.parseNumericAddress("192.0.2.201");
+    private static final InetAddress TEST_VPN_INTERNAL_IP =
+            InetAddresses.parseNumericAddress("198.51.100.10");
+    private static final InetAddress TEST_VPN_INTERNAL_IP6 =
+            InetAddresses.parseNumericAddress("2001:db8::1");
+    private static final InetAddress TEST_VPN_INTERNAL_DNS =
+            InetAddresses.parseNumericAddress("8.8.8.8");
+    private static final InetAddress TEST_VPN_INTERNAL_DNS6 =
+            InetAddresses.parseNumericAddress("2001:4860:4860::8888");
+
+    private static final IkeTrafficSelector IN_TS =
+            new IkeTrafficSelector(MIN_PORT, MAX_PORT, TEST_VPN_INTERNAL_IP, TEST_VPN_INTERNAL_IP);
+    private static final IkeTrafficSelector IN_TS6 =
+            new IkeTrafficSelector(
+                    MIN_PORT, MAX_PORT, TEST_VPN_INTERNAL_IP6, TEST_VPN_INTERNAL_IP6);
+    private static final IkeTrafficSelector OUT_TS =
+            new IkeTrafficSelector(MIN_PORT, MAX_PORT,
+                    InetAddresses.parseNumericAddress("0.0.0.0"),
+                    InetAddresses.parseNumericAddress("255.255.255.255"));
+    private static final IkeTrafficSelector OUT_TS6 =
+            new IkeTrafficSelector(
+                    MIN_PORT,
+                    MAX_PORT,
+                    InetAddresses.parseNumericAddress("::"),
+                    InetAddresses.parseNumericAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"));
+
+    private static final Network TEST_NETWORK = new Network(Integer.MAX_VALUE);
+    private static final Network TEST_NETWORK_2 = new Network(Integer.MAX_VALUE - 1);
+    private static final String TEST_IFACE_NAME = "TEST_IFACE";
+    private static final int TEST_TUNNEL_RESOURCE_ID = 0x2345;
+    private static final long TEST_TIMEOUT_MS = 500L;
+    private static final long TIMEOUT_CROSSTHREAD_MS = 20_000L;
+    private static final String PRIMARY_USER_APP_EXCLUDE_KEY =
+            "VPNAPPEXCLUDED_27_com.testvpn.vpn";
+    static final String PKGS_BYTES = getPackageByteString(List.of(PKGS));
+    private static final Range<Integer> PRIMARY_USER_RANGE = uidRangeForUser(PRIMARY_USER.id);
+    private static final int TEST_KEEPALIVE_TIMER = 800;
+    private static final int TEST_SUB_ID = 1234;
+    private static final String TEST_MCCMNC = "12345";
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
+    @Mock private UserManager mUserManager;
+    @Mock private PackageManager mPackageManager;
+    @Mock private INetworkManagementService mNetService;
+    @Mock private INetd mNetd;
+    @Mock private AppOpsManager mAppOps;
+    @Mock private NotificationManager mNotificationManager;
+    @Mock private Vpn.SystemServices mSystemServices;
+    @Mock private Vpn.IkeSessionWrapper mIkeSessionWrapper;
+    @Mock private Vpn.Ikev2SessionCreator mIkev2SessionCreator;
+    @Mock private Vpn.VpnNetworkAgentWrapper mMockNetworkAgent;
+    @Mock private ConnectivityManager mConnectivityManager;
+    @Mock private ConnectivityDiagnosticsManager mCdm;
+    @Mock private TelephonyManager mTelephonyManager;
+    @Mock private TelephonyManager mTmPerSub;
+    @Mock private CarrierConfigManager mConfigManager;
+    @Mock private SubscriptionManager mSubscriptionManager;
+    @Mock private IpSecService mIpSecService;
+    @Mock private VpnProfileStore mVpnProfileStore;
+    private final TestExecutor mExecutor;
+    @Mock DeviceIdleInternal mDeviceIdleInternal;
+    private final VpnProfile mVpnProfile;
+
+    @Captor private ArgumentCaptor<Collection<Range<Integer>>> mUidRangesCaptor;
+
+    private IpSecManager mIpSecManager;
+    private TestDeps mTestDeps;
+
+    public static class TestExecutor extends ScheduledThreadPoolExecutor {
+        public static final long REAL_DELAY = -1;
+
+        // For the purposes of the test, run all scheduled tasks after 10ms to save
+        // execution time, unless overridden by the specific test. Set to REAL_DELAY
+        // to actually wait for the delay specified by the real call to schedule().
+        public long delayMs = 10;
+        // If this is true, execute() will call the runnable inline. This is useful because
+        // super.execute() calls schedule(), which messes with checks that scheduled() is
+        // called a given number of times.
+        public boolean executeDirect = false;
+
+        public TestExecutor() {
+            super(1);
+        }
+
+        @Override
+        public void execute(final Runnable command) {
+            // See |executeDirect| for why this is necessary.
+            if (executeDirect) {
+                command.run();
+            } else {
+                super.execute(command);
+            }
+        }
+
+        @Override
+        public ScheduledFuture<?> schedule(final Runnable command, final long delay,
+                TimeUnit unit) {
+            if (0 == delay || delayMs == REAL_DELAY) {
+                // super.execute() calls schedule() with 0, so use the real delay if it's 0.
+                return super.schedule(command, delay, unit);
+            } else {
+                return super.schedule(command, delayMs, TimeUnit.MILLISECONDS);
+            }
+        }
+    }
+
+    public VpnTest() throws Exception {
+        // Build an actual VPN profile that is capable of being converted to and from an
+        // Ikev2VpnProfile
+        final Ikev2VpnProfile.Builder builder =
+                new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY);
+        builder.setAuthPsk(TEST_VPN_PSK);
+        builder.setBypassable(true /* isBypassable */);
+        mExecutor = spy(new TestExecutor());
+        mVpnProfile = builder.build().toVpnProfile();
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mIpSecManager = new IpSecManager(mContext, mIpSecService);
+        mTestDeps = spy(new TestDeps());
+        doReturn(IPV6_MIN_MTU)
+                .when(mTestDeps)
+                .calculateVpnMtu(any(), anyInt(), anyInt(), anyBoolean());
+        doReturn(1500).when(mTestDeps).getJavaNetworkInterfaceMtu(any(), anyInt());
+
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        setMockedPackages(sPackages);
+
+        when(mContext.getPackageName()).thenReturn(TEST_VPN_PKG);
+        when(mContext.getOpPackageName()).thenReturn(TEST_VPN_PKG);
+        mockService(UserManager.class, Context.USER_SERVICE, mUserManager);
+        mockService(AppOpsManager.class, Context.APP_OPS_SERVICE, mAppOps);
+        mockService(NotificationManager.class, Context.NOTIFICATION_SERVICE, mNotificationManager);
+        mockService(ConnectivityManager.class, Context.CONNECTIVITY_SERVICE, mConnectivityManager);
+        mockService(IpSecManager.class, Context.IPSEC_SERVICE, mIpSecManager);
+        mockService(ConnectivityDiagnosticsManager.class, Context.CONNECTIVITY_DIAGNOSTICS_SERVICE,
+                mCdm);
+        mockService(TelephonyManager.class, Context.TELEPHONY_SERVICE, mTelephonyManager);
+        mockService(CarrierConfigManager.class, Context.CARRIER_CONFIG_SERVICE, mConfigManager);
+        mockService(SubscriptionManager.class, Context.TELEPHONY_SUBSCRIPTION_SERVICE,
+                mSubscriptionManager);
+        doReturn(mTmPerSub).when(mTelephonyManager).createForSubscriptionId(anyInt());
+        when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
+                .thenReturn(Resources.getSystem().getString(
+                        R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS))
+                .thenReturn(true);
+
+        // Used by {@link Notification.Builder}
+        ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
+        when(mContext.getApplicationInfo()).thenReturn(applicationInfo);
+        when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
+                .thenReturn(applicationInfo);
+
+        doNothing().when(mNetService).registerObserver(any());
+
+        // Deny all appops by default.
+        when(mAppOps.noteOpNoThrow(anyString(), anyInt(), anyString(), any(), any()))
+                .thenReturn(AppOpsManager.MODE_IGNORED);
+
+        // Setup IpSecService
+        final IpSecTunnelInterfaceResponse tunnelResp =
+                new IpSecTunnelInterfaceResponse(
+                        IpSecManager.Status.OK, TEST_TUNNEL_RESOURCE_ID, TEST_IFACE_NAME);
+        when(mIpSecService.createTunnelInterface(any(), any(), any(), any(), any()))
+                .thenReturn(tunnelResp);
+        doReturn(new LinkProperties()).when(mConnectivityManager).getLinkProperties(any());
+
+        // The unit test should know what kind of permission it needs and set the permission by
+        // itself, so set the default value of Context#checkCallingOrSelfPermission to
+        // PERMISSION_DENIED.
+        doReturn(PERMISSION_DENIED).when(mContext).checkCallingOrSelfPermission(any());
+
+        // Set up mIkev2SessionCreator and mExecutor
+        resetIkev2SessionCreator(mIkeSessionWrapper);
+    }
+
+    private void resetIkev2SessionCreator(Vpn.IkeSessionWrapper ikeSession) {
+        reset(mIkev2SessionCreator);
+        when(mIkev2SessionCreator.createIkeSession(any(), any(), any(), any(), any(), any()))
+                .thenReturn(ikeSession);
+    }
+
+    private <T> void mockService(Class<T> clazz, String name, T service) {
+        doReturn(service).when(mContext).getSystemService(name);
+        doReturn(name).when(mContext).getSystemServiceName(clazz);
+        if (mContext.getSystemService(clazz).getClass().equals(Object.class)) {
+            // Test is using mockito-extended (mContext uses Answers.RETURNS_DEEP_STUBS and returned
+            // a mock object on a final method)
+            doCallRealMethod().when(mContext).getSystemService(clazz);
+        }
+    }
+
+    private Set<Range<Integer>> rangeSet(Range<Integer> ... ranges) {
+        final Set<Range<Integer>> range = new ArraySet<>();
+        for (Range<Integer> r : ranges) range.add(r);
+
+        return range;
+    }
+
+    private static Range<Integer> uidRangeForUser(int userId) {
+        return new Range<Integer>(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1);
+    }
+
+    private Range<Integer> uidRange(int start, int stop) {
+        return new Range<Integer>(start, stop);
+    }
+
+    private static String getPackageByteString(List<String> packages) {
+        try {
+            return HexDump.toHexString(
+                    PersistableBundleUtils.toDiskStableBytes(PersistableBundleUtils.fromList(
+                            packages, PersistableBundleUtils.STRING_SERIALIZER)),
+                        true /* upperCase */);
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    @Test
+    public void testRestrictedProfilesAreAddedToVpn() {
+        setMockedUsers(PRIMARY_USER, SECONDARY_USER, RESTRICTED_PROFILE_A, RESTRICTED_PROFILE_B);
+
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+
+        // Assume the user can have restricted profiles.
+        doReturn(true).when(mUserManager).canHaveRestrictedProfile();
+        final Set<Range<Integer>> ranges =
+                vpn.createUserAndRestrictedProfilesRanges(PRIMARY_USER.id, null, null);
+
+        assertEquals(rangeSet(PRIMARY_USER_RANGE, uidRangeForUser(RESTRICTED_PROFILE_A.id)),
+                 ranges);
+    }
+
+    @Test
+    public void testManagedProfilesAreNotAddedToVpn() {
+        setMockedUsers(PRIMARY_USER, MANAGED_PROFILE_A);
+
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+        final Set<Range<Integer>> ranges = vpn.createUserAndRestrictedProfilesRanges(
+                PRIMARY_USER.id, null, null);
+
+        assertEquals(rangeSet(PRIMARY_USER_RANGE), ranges);
+    }
+
+    @Test
+    public void testAddUserToVpnOnlyAddsOneUser() {
+        setMockedUsers(PRIMARY_USER, RESTRICTED_PROFILE_A, MANAGED_PROFILE_A);
+
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+        final Set<Range<Integer>> ranges = new ArraySet<>();
+        vpn.addUserToRanges(ranges, PRIMARY_USER.id, null, null);
+
+        assertEquals(rangeSet(PRIMARY_USER_RANGE), ranges);
+    }
+
+    @Test
+    public void testUidAllowAndDenylist() throws Exception {
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+        final Range<Integer> user = PRIMARY_USER_RANGE;
+        final int userStart = user.getLower();
+        final int userStop = user.getUpper();
+        final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
+
+        // Allowed list
+        final Set<Range<Integer>> allow = vpn.createUserAndRestrictedProfilesRanges(PRIMARY_USER.id,
+                Arrays.asList(packages), null /* disallowedApplications */);
+        assertEquals(rangeSet(
+                uidRange(userStart + PKG_UIDS[0], userStart + PKG_UIDS[0]),
+                uidRange(userStart + PKG_UIDS[1], userStart + PKG_UIDS[2]),
+                uidRange(Process.toSdkSandboxUid(userStart + PKG_UIDS[0]),
+                         Process.toSdkSandboxUid(userStart + PKG_UIDS[0])),
+                uidRange(Process.toSdkSandboxUid(userStart + PKG_UIDS[1]),
+                         Process.toSdkSandboxUid(userStart + PKG_UIDS[2]))),
+                allow);
+
+        // Denied list
+        final Set<Range<Integer>> disallow =
+                vpn.createUserAndRestrictedProfilesRanges(PRIMARY_USER.id,
+                        null /* allowedApplications */, Arrays.asList(packages));
+        assertEquals(rangeSet(
+                uidRange(userStart, userStart + PKG_UIDS[0] - 1),
+                uidRange(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
+                /* Empty range between UIDS[1] and UIDS[2], should be excluded, */
+                uidRange(userStart + PKG_UIDS[2] + 1,
+                         Process.toSdkSandboxUid(userStart + PKG_UIDS[0] - 1)),
+                uidRange(Process.toSdkSandboxUid(userStart + PKG_UIDS[0] + 1),
+                         Process.toSdkSandboxUid(userStart + PKG_UIDS[1] - 1)),
+                uidRange(Process.toSdkSandboxUid(userStart + PKG_UIDS[2] + 1), userStop)),
+                disallow);
+    }
+
+    private void verifyPowerSaveTempWhitelistApp(String packageName) {
+        verify(mDeviceIdleInternal, timeout(TEST_TIMEOUT_MS)).addPowerSaveTempWhitelistApp(
+                anyInt(), eq(packageName), anyLong(), anyInt(), eq(false),
+                eq(PowerWhitelistManager.REASON_VPN), eq("VpnManager event"));
+    }
+
+    @Test
+    public void testGetAlwaysAndOnGetLockDown() throws Exception {
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+
+        // Default state.
+        assertFalse(vpn.getAlwaysOn());
+        assertFalse(vpn.getLockdown());
+
+        // Set always-on without lockdown.
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList()));
+        assertTrue(vpn.getAlwaysOn());
+        assertFalse(vpn.getLockdown());
+
+        // Set always-on with lockdown.
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList()));
+        assertTrue(vpn.getAlwaysOn());
+        assertTrue(vpn.getLockdown());
+
+        // Remove always-on configuration.
+        assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList()));
+        assertFalse(vpn.getAlwaysOn());
+        assertFalse(vpn.getLockdown());
+    }
+
+    @Test
+    public void testAlwaysOnWithoutLockdown() throws Exception {
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+        assertTrue(vpn.setAlwaysOnPackage(
+                PKGS[1], false /* lockdown */, null /* lockdownAllowlist */));
+        verify(mConnectivityManager, never()).setRequireVpnForUids(anyBoolean(), any());
+
+        assertTrue(vpn.setAlwaysOnPackage(
+                null /* packageName */, false /* lockdown */, null /* lockdownAllowlist */));
+        verify(mConnectivityManager, never()).setRequireVpnForUids(anyBoolean(), any());
+    }
+
+    @Test
+    public void testLockdownChangingPackage() throws Exception {
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+        final Range<Integer> user = PRIMARY_USER_RANGE;
+        final int userStart = user.getLower();
+        final int userStop = user.getUpper();
+        // Set always-on without lockdown.
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null));
+
+        // Set always-on with lockdown.
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null));
+        verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
+                new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[1] + 1,
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[1] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[1] + 1), userStop)
+        }));
+
+        // Switch to another app.
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
+        verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
+                new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[1] + 1,
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[1] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[1] + 1), userStop)
+        }));
+        verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
+                new UidRangeParcel(userStart, userStart + PKG_UIDS[3] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[3] + 1,
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[3] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[3] + 1), userStop)
+        }));
+    }
+
+    @Test
+    public void testLockdownAllowlist() throws Exception {
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+        final Range<Integer> user = PRIMARY_USER_RANGE;
+        final int userStart = user.getLower();
+        final int userStop = user.getUpper();
+        // Set always-on with lockdown and allow app PKGS[2] from lockdown.
+        assertTrue(vpn.setAlwaysOnPackage(
+                PKGS[1], true, Collections.singletonList(PKGS[2])));
+        verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[]  {
+                new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[2] + 1,
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[1]) - 1),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[2] + 1), userStop)
+        }));
+        // Change allowed app list to PKGS[3].
+        assertTrue(vpn.setAlwaysOnPackage(
+                PKGS[1], true, Collections.singletonList(PKGS[3])));
+        verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
+                new UidRangeParcel(userStart + PKG_UIDS[2] + 1,
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[1] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[2] + 1), userStop)
+        }));
+        verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
+                new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[3] + 1,
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[1] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[1] + 1),
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[3] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[3] + 1), userStop)
+        }));
+
+        // Change the VPN app.
+        assertTrue(vpn.setAlwaysOnPackage(
+                PKGS[0], true, Collections.singletonList(PKGS[3])));
+        verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
+                new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[3] + 1,
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[1] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[1] + 1),
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[3] - 1))
+        }));
+        verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
+                new UidRangeParcel(userStart, userStart + PKG_UIDS[0] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[3] + 1,
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[0] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[0] + 1),
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[3] - 1))
+        }));
+
+        // Remove the list of allowed packages.
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null));
+        verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
+                new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[3] + 1,
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[0] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[0] + 1),
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[3] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[3] + 1), userStop)
+        }));
+        verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
+                new UidRangeParcel(userStart + PKG_UIDS[0] + 1,
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[0] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[0] + 1), userStop),
+        }));
+
+        // Add the list of allowed packages.
+        assertTrue(vpn.setAlwaysOnPackage(
+                PKGS[0], true, Collections.singletonList(PKGS[1])));
+        verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
+                new UidRangeParcel(userStart + PKG_UIDS[0] + 1,
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[0] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[0] + 1), userStop),
+        }));
+        verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
+                new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[1] + 1,
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[0] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[0] + 1),
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[1] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[1] + 1), userStop)
+        }));
+
+        // Try allowing a package with a comma, should be rejected.
+        assertFalse(vpn.setAlwaysOnPackage(
+                PKGS[0], true, Collections.singletonList("a.b,c.d")));
+
+        // Pass a non-existent packages in the allowlist, they (and only they) should be ignored.
+        // allowed package should change from PGKS[1] to PKGS[2].
+        assertTrue(vpn.setAlwaysOnPackage(
+                PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app")));
+        verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
+                new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[1] + 1,
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[0] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[0] + 1),
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[1] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[1] + 1), userStop)
+        }));
+        verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
+                new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[2] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[2] + 1,
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[0] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[0] + 1),
+                                   Process.toSdkSandboxUid(userStart + PKG_UIDS[2] - 1)),
+                new UidRangeParcel(Process.toSdkSandboxUid(userStart + PKG_UIDS[2] + 1), userStop)
+        }));
+    }
+
+    @Test
+    public void testLockdownSystemUser() throws Exception {
+        final Vpn vpn = createVpn(SYSTEM_USER_ID);
+
+        // Uid 0 is always excluded and PKG_UIDS[1] is the uid of the VPN.
+        final List<Integer> excludedUids = new ArrayList<>(List.of(0, PKG_UIDS[1]));
+        final List<Range<Integer>> ranges = makeVpnUidRange(SYSTEM_USER_ID, excludedUids);
+
+        // Set always-on with lockdown.
+        assertTrue(vpn.setAlwaysOnPackage(
+                PKGS[1], true /* lockdown */, null /* lockdownAllowlist */));
+        verify(mConnectivityManager).setRequireVpnForUids(true, ranges);
+
+        // Disable always-on with lockdown.
+        assertTrue(vpn.setAlwaysOnPackage(
+                null /* packageName */, false /* lockdown */, null /* lockdownAllowlist */));
+        verify(mConnectivityManager).setRequireVpnForUids(false, ranges);
+
+        // Set always-on with lockdown and allow the app PKGS[2].
+        excludedUids.add(PKG_UIDS[2]);
+        final List<Range<Integer>> ranges2 = makeVpnUidRange(SYSTEM_USER_ID, excludedUids);
+        assertTrue(vpn.setAlwaysOnPackage(
+                PKGS[1], true /* lockdown */, Collections.singletonList(PKGS[2])));
+        verify(mConnectivityManager).setRequireVpnForUids(true, ranges2);
+
+        // Disable always-on with lockdown.
+        assertTrue(vpn.setAlwaysOnPackage(
+                null /* packageName */, false /* lockdown */, null /* lockdownAllowlist */));
+        verify(mConnectivityManager).setRequireVpnForUids(false, ranges2);
+    }
+
+    @Test
+    public void testLockdownRuleRepeatability() throws Exception {
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+        final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] {
+                new UidRangeParcel(PRIMARY_USER_RANGE.getLower(), PRIMARY_USER_RANGE.getUpper())};
+        // Given legacy lockdown is already enabled,
+        vpn.setLockdown(true);
+        verify(mConnectivityManager, times(1)).setRequireVpnForUids(true,
+                toRanges(primaryUserRangeParcel));
+
+        // Enabling legacy lockdown twice should do nothing.
+        vpn.setLockdown(true);
+        verify(mConnectivityManager, times(1)).setRequireVpnForUids(anyBoolean(), any());
+
+        // And disabling should remove the rules exactly once.
+        vpn.setLockdown(false);
+        verify(mConnectivityManager, times(1)).setRequireVpnForUids(false,
+                toRanges(primaryUserRangeParcel));
+
+        // Removing the lockdown again should have no effect.
+        vpn.setLockdown(false);
+        verify(mConnectivityManager, times(2)).setRequireVpnForUids(anyBoolean(), any());
+    }
+
+    private ArrayList<Range<Integer>> toRanges(UidRangeParcel[] ranges) {
+        ArrayList<Range<Integer>> rangesArray = new ArrayList<>(ranges.length);
+        for (int i = 0; i < ranges.length; i++) {
+            rangesArray.add(new Range<>(ranges[i].start, ranges[i].stop));
+        }
+        return rangesArray;
+    }
+
+    @Test
+    public void testLockdownRuleReversibility() throws Exception {
+        doReturn(PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission(CONTROL_VPN);
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+        final UidRangeParcel[] entireUser = {
+            new UidRangeParcel(PRIMARY_USER_RANGE.getLower(), PRIMARY_USER_RANGE.getUpper())
+        };
+        final UidRangeParcel[] exceptPkg0 = {
+            new UidRangeParcel(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
+            new UidRangeParcel(entireUser[0].start + PKG_UIDS[0] + 1,
+                               Process.toSdkSandboxUid(entireUser[0].start + PKG_UIDS[0] - 1)),
+            new UidRangeParcel(Process.toSdkSandboxUid(entireUser[0].start + PKG_UIDS[0] + 1),
+                               entireUser[0].stop),
+        };
+
+        final InOrder order = inOrder(mConnectivityManager);
+
+        // Given lockdown is enabled with no package (legacy VPN),
+        vpn.setLockdown(true);
+        order.verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(entireUser));
+
+        // When a new VPN package is set the rules should change to cover that package.
+        vpn.prepare(null, PKGS[0], VpnManager.TYPE_VPN_SERVICE);
+        order.verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(entireUser));
+        order.verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(exceptPkg0));
+
+        // When that VPN package is unset, everything should be undone again in reverse.
+        vpn.prepare(null, VpnConfig.LEGACY_VPN, VpnManager.TYPE_VPN_SERVICE);
+        order.verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(exceptPkg0));
+        order.verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(entireUser));
+    }
+
+    @Test
+    public void testOnUserAddedAndRemoved_restrictedUser() throws Exception {
+        final InOrder order = inOrder(mMockNetworkAgent);
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+        final Set<Range<Integer>> initialRange = rangeSet(PRIMARY_USER_RANGE);
+        // Note since mVpnProfile is a Ikev2VpnProfile, this starts an IkeV2VpnRunner.
+        startLegacyVpn(vpn, mVpnProfile);
+        // Set an initial Uid range and mock the network agent
+        vpn.mNetworkCapabilities.setUids(initialRange);
+        vpn.mNetworkAgent = mMockNetworkAgent;
+
+        // Add the restricted user
+        setMockedUsers(PRIMARY_USER, RESTRICTED_PROFILE_A);
+        vpn.onUserAdded(RESTRICTED_PROFILE_A.id);
+        // Expect restricted user range to be added to the NetworkCapabilities.
+        final Set<Range<Integer>> expectRestrictedRange =
+                rangeSet(PRIMARY_USER_RANGE, uidRangeForUser(RESTRICTED_PROFILE_A.id));
+        assertEquals(expectRestrictedRange, vpn.mNetworkCapabilities.getUids());
+        order.verify(mMockNetworkAgent).doSendNetworkCapabilities(
+                argThat(nc -> expectRestrictedRange.equals(nc.getUids())));
+
+        // Remove the restricted user
+        vpn.onUserRemoved(RESTRICTED_PROFILE_A.id);
+        // Expect restricted user range to be removed from the NetworkCapabilities.
+        assertEquals(initialRange, vpn.mNetworkCapabilities.getUids());
+        order.verify(mMockNetworkAgent).doSendNetworkCapabilities(
+                argThat(nc -> initialRange.equals(nc.getUids())));
+    }
+
+    @Test
+    public void testOnUserAddedAndRemoved_restrictedUserLockdown() throws Exception {
+        final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] {
+                new UidRangeParcel(PRIMARY_USER_RANGE.getLower(), PRIMARY_USER_RANGE.getUpper())};
+        final Range<Integer> restrictedUserRange = uidRangeForUser(RESTRICTED_PROFILE_A.id);
+        final UidRangeParcel[] restrictedUserRangeParcel = new UidRangeParcel[] {
+                new UidRangeParcel(restrictedUserRange.getLower(), restrictedUserRange.getUpper())};
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+
+        // Set lockdown calls setRequireVpnForUids
+        vpn.setLockdown(true);
+        verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(primaryUserRangeParcel));
+
+        // Add the restricted user
+        doReturn(true).when(mUserManager).canHaveRestrictedProfile();
+        setMockedUsers(PRIMARY_USER, RESTRICTED_PROFILE_A);
+        vpn.onUserAdded(RESTRICTED_PROFILE_A.id);
+
+        // Expect restricted user range to be added.
+        verify(mConnectivityManager).setRequireVpnForUids(true,
+                toRanges(restrictedUserRangeParcel));
+
+        // Mark as partial indicates that the user is removed, mUserManager.getAliveUsers() does not
+        // return the restricted user but it is still returned in mUserManager.getUserInfo().
+        RESTRICTED_PROFILE_A.partial = true;
+        // Remove the restricted user
+        vpn.onUserRemoved(RESTRICTED_PROFILE_A.id);
+        verify(mConnectivityManager).setRequireVpnForUids(false,
+                toRanges(restrictedUserRangeParcel));
+        // reset to avoid affecting other tests since RESTRICTED_PROFILE_A is static.
+        RESTRICTED_PROFILE_A.partial = false;
+    }
+
+    @Test
+    public void testOnUserAddedAndRemoved_restrictedUserAlwaysOn() throws Exception {
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+
+        // setAlwaysOnPackage() calls setRequireVpnForUids()
+        assertTrue(vpn.setAlwaysOnPackage(
+                PKGS[0], true /* lockdown */, null /* lockdownAllowlist */));
+        final List<Integer> excludedUids = List.of(PKG_UIDS[0]);
+        final List<Range<Integer>> primaryRanges =
+                makeVpnUidRange(PRIMARY_USER.id, excludedUids);
+        verify(mConnectivityManager).setRequireVpnForUids(true, primaryRanges);
+
+        // Add the restricted user
+        doReturn(true).when(mUserManager).canHaveRestrictedProfile();
+        setMockedUsers(PRIMARY_USER, RESTRICTED_PROFILE_A);
+        vpn.onUserAdded(RESTRICTED_PROFILE_A.id);
+
+        final List<Range<Integer>> restrictedRanges =
+                makeVpnUidRange(RESTRICTED_PROFILE_A.id, excludedUids);
+        // Expect restricted user range to be added.
+        verify(mConnectivityManager).setRequireVpnForUids(true, restrictedRanges);
+
+        // Mark as partial indicates that the user is removed, mUserManager.getAliveUsers() does not
+        // return the restricted user but it is still returned in mUserManager.getUserInfo().
+        RESTRICTED_PROFILE_A.partial = true;
+        // Remove the restricted user
+        vpn.onUserRemoved(RESTRICTED_PROFILE_A.id);
+        verify(mConnectivityManager).setRequireVpnForUids(false, restrictedRanges);
+
+        // reset to avoid affecting other tests since RESTRICTED_PROFILE_A is static.
+        RESTRICTED_PROFILE_A.partial = false;
+    }
+
+    @Test
+    public void testPrepare_throwSecurityExceptionWhenGivenPackageDoesNotBelongToTheCaller()
+            throws Exception {
+        mTestDeps.mIgnoreCallingUidChecks = false;
+        final Vpn vpn = createVpn();
+        assertThrows(SecurityException.class,
+                () -> vpn.prepare("com.not.vpn.owner", null, VpnManager.TYPE_VPN_SERVICE));
+        assertThrows(SecurityException.class,
+                () -> vpn.prepare(null, "com.not.vpn.owner", VpnManager.TYPE_VPN_SERVICE));
+        assertThrows(SecurityException.class,
+                () -> vpn.prepare("com.not.vpn.owner1", "com.not.vpn.owner2",
+                        VpnManager.TYPE_VPN_SERVICE));
+    }
+
+    @Test
+    public void testPrepare_bothOldPackageAndNewPackageAreNull() throws Exception {
+        final Vpn vpn = createVpn();
+        assertTrue(vpn.prepare(null, null, VpnManager.TYPE_VPN_SERVICE));
+
+    }
+
+    @Test
+    public void testPrepare_legacyVpnWithoutControlVpn()
+            throws Exception {
+        doThrow(new SecurityException("no CONTROL_VPN")).when(mContext)
+                .enforceCallingOrSelfPermission(eq(CONTROL_VPN), any());
+        final Vpn vpn = createVpn();
+        assertThrows(SecurityException.class,
+                () -> vpn.prepare(null, VpnConfig.LEGACY_VPN, VpnManager.TYPE_VPN_SERVICE));
+
+        // CONTROL_VPN can be held by the caller or another system server process - both are
+        // allowed. Just checking for `enforceCallingPermission` may not be sufficient.
+        verify(mContext, never()).enforceCallingPermission(eq(CONTROL_VPN), any());
+    }
+
+    @Test
+    public void testPrepare_legacyVpnWithControlVpn()
+            throws Exception {
+        doNothing().when(mContext).enforceCallingOrSelfPermission(eq(CONTROL_VPN), any());
+        final Vpn vpn = createVpn();
+        assertTrue(vpn.prepare(null, VpnConfig.LEGACY_VPN, VpnManager.TYPE_VPN_SERVICE));
+
+        // CONTROL_VPN can be held by the caller or another system server process - both are
+        // allowed. Just checking for `enforceCallingPermission` may not be sufficient.
+        verify(mContext, never()).enforceCallingPermission(eq(CONTROL_VPN), any());
+    }
+
+    @Test
+    public void testIsAlwaysOnPackageSupported() throws Exception {
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+
+        ApplicationInfo appInfo = new ApplicationInfo();
+        when(mPackageManager.getApplicationInfoAsUser(eq(PKGS[0]), anyInt(), eq(PRIMARY_USER.id)))
+                .thenReturn(appInfo);
+
+        ServiceInfo svcInfo = new ServiceInfo();
+        ResolveInfo resInfo = new ResolveInfo();
+        resInfo.serviceInfo = svcInfo;
+        when(mPackageManager.queryIntentServicesAsUser(any(), eq(PackageManager.GET_META_DATA),
+                eq(PRIMARY_USER.id)))
+                .thenReturn(Collections.singletonList(resInfo));
+
+        // null package name should return false
+        assertFalse(vpn.isAlwaysOnPackageSupported(null));
+
+        // Pre-N apps are not supported
+        appInfo.targetSdkVersion = VERSION_CODES.M;
+        assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
+
+        // N+ apps are supported by default
+        appInfo.targetSdkVersion = VERSION_CODES.N;
+        assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0]));
+
+        // Apps that opt out explicitly are not supported
+        appInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
+        Bundle metaData = new Bundle();
+        metaData.putBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, false);
+        svcInfo.metaData = metaData;
+        assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
+    }
+
+    @Test
+    public void testNotificationShownForAlwaysOnApp() throws Exception {
+        final UserHandle userHandle = UserHandle.of(PRIMARY_USER.id);
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+        setMockedUsers(PRIMARY_USER);
+
+        final InOrder order = inOrder(mNotificationManager);
+
+        // Don't show a notification for regular disconnected states.
+        vpn.updateState(DetailedState.DISCONNECTED, TAG);
+        order.verify(mNotificationManager, atLeastOnce()).cancel(anyString(), anyInt());
+
+        // Start showing a notification for disconnected once always-on.
+        vpn.setAlwaysOnPackage(PKGS[0], false, null);
+        order.verify(mNotificationManager).notify(anyString(), anyInt(), any());
+
+        // Stop showing the notification once connected.
+        vpn.updateState(DetailedState.CONNECTED, TAG);
+        order.verify(mNotificationManager).cancel(anyString(), anyInt());
+
+        // Show the notification if we disconnect again.
+        vpn.updateState(DetailedState.DISCONNECTED, TAG);
+        order.verify(mNotificationManager).notify(anyString(), anyInt(), any());
+
+        // Notification should be cleared after unsetting always-on package.
+        vpn.setAlwaysOnPackage(null, false, null);
+        order.verify(mNotificationManager).cancel(anyString(), anyInt());
+    }
+
+    /**
+     * The profile name should NOT change between releases for backwards compatibility
+     *
+     * <p>If this is changed between releases, the {@link Vpn#getVpnProfilePrivileged()} method MUST
+     * be updated to ensure backward compatibility.
+     */
+    @Test
+    public void testGetProfileNameForPackage() throws Exception {
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+        setMockedUsers(PRIMARY_USER);
+
+        final String expected = Credentials.PLATFORM_VPN + PRIMARY_USER.id + "_" + TEST_VPN_PKG;
+        assertEquals(expected, vpn.getProfileNameForPackage(TEST_VPN_PKG));
+    }
+
+    private Vpn createVpn(String... grantedOps) throws Exception {
+        return createVpn(PRIMARY_USER, grantedOps);
+    }
+
+    private Vpn createVpn(UserInfo user, String... grantedOps) throws Exception {
+        final Vpn vpn = createVpn(user.id);
+        setMockedUsers(user);
+
+        for (final String opStr : grantedOps) {
+            when(mAppOps.noteOpNoThrow(opStr, Process.myUid(), TEST_VPN_PKG,
+                    null /* attributionTag */, null /* message */))
+                    .thenReturn(AppOpsManager.MODE_ALLOWED);
+        }
+
+        return vpn;
+    }
+
+    private void checkProvisionVpnProfile(Vpn vpn, boolean expectedResult, String... checkedOps) {
+        assertEquals(expectedResult, vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile));
+
+        // The profile should always be stored, whether or not consent has been previously granted.
+        verify(mVpnProfileStore)
+                .put(
+                        eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)),
+                        eq(mVpnProfile.encode()));
+
+        for (final String checkedOpStr : checkedOps) {
+            verify(mAppOps).noteOpNoThrow(checkedOpStr, Process.myUid(), TEST_VPN_PKG,
+                    null /* attributionTag */, null /* message */);
+        }
+    }
+
+    @Test
+    public void testProvisionVpnProfileNoIpsecTunnels() throws Exception {
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS))
+                .thenReturn(false);
+        final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+
+        try {
+            checkProvisionVpnProfile(
+                    vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+            fail("Expected exception due to missing feature");
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    private String startVpnForVerifyAppExclusionList(Vpn vpn) throws Exception {
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+                .thenReturn(mVpnProfile.encode());
+        when(mVpnProfileStore.get(PRIMARY_USER_APP_EXCLUDE_KEY))
+                .thenReturn(HexDump.hexStringToByteArray(PKGS_BYTES));
+        final String sessionKey = vpn.startVpnProfile(TEST_VPN_PKG);
+        final Set<Range<Integer>> uidRanges = vpn.createUserAndRestrictedProfilesRanges(
+                PRIMARY_USER.id, null /* allowedApplications */, Arrays.asList(PKGS));
+        verify(mConnectivityManager).setVpnDefaultForUids(eq(sessionKey), eq(uidRanges));
+        clearInvocations(mConnectivityManager);
+        verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
+        vpn.mNetworkAgent = mMockNetworkAgent;
+
+        return sessionKey;
+    }
+
+    private Vpn prepareVpnForVerifyAppExclusionList() throws Exception {
+        final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+        startVpnForVerifyAppExclusionList(vpn);
+
+        return vpn;
+    }
+
+    @Test
+    public void testSetAndGetAppExclusionList() throws Exception {
+        final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+        final String sessionKey = startVpnForVerifyAppExclusionList(vpn);
+        verify(mVpnProfileStore, never()).put(eq(PRIMARY_USER_APP_EXCLUDE_KEY), any());
+        vpn.setAppExclusionList(TEST_VPN_PKG, Arrays.asList(PKGS));
+        verify(mVpnProfileStore)
+                .put(eq(PRIMARY_USER_APP_EXCLUDE_KEY),
+                     eq(HexDump.hexStringToByteArray(PKGS_BYTES)));
+        final Set<Range<Integer>> uidRanges = vpn.createUserAndRestrictedProfilesRanges(
+                PRIMARY_USER.id, null /* allowedApplications */, Arrays.asList(PKGS));
+        verify(mConnectivityManager).setVpnDefaultForUids(eq(sessionKey), eq(uidRanges));
+        assertEquals(uidRanges, vpn.mNetworkCapabilities.getUids());
+        assertEquals(Arrays.asList(PKGS), vpn.getAppExclusionList(TEST_VPN_PKG));
+    }
+
+    @Test
+    public void testRefreshPlatformVpnAppExclusionList_updatesExcludedUids() throws Exception {
+        final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+        final String sessionKey = startVpnForVerifyAppExclusionList(vpn);
+        vpn.setAppExclusionList(TEST_VPN_PKG, Arrays.asList(PKGS));
+        final Set<Range<Integer>> uidRanges = vpn.createUserAndRestrictedProfilesRanges(
+                PRIMARY_USER.id, null /* allowedApplications */, Arrays.asList(PKGS));
+        verify(mConnectivityManager).setVpnDefaultForUids(eq(sessionKey), eq(uidRanges));
+        verify(mMockNetworkAgent).doSendNetworkCapabilities(any());
+        assertEquals(Arrays.asList(PKGS), vpn.getAppExclusionList(TEST_VPN_PKG));
+
+        reset(mMockNetworkAgent);
+
+        // Remove one of the package
+        List<Integer> newExcludedUids = toList(PKG_UIDS);
+        newExcludedUids.remove((Integer) PKG_UIDS[0]);
+        Set<Range<Integer>> newUidRanges = makeVpnUidRangeSet(PRIMARY_USER.id, newExcludedUids);
+        sPackages.remove(PKGS[0]);
+        vpn.refreshPlatformVpnAppExclusionList();
+
+        // List in keystore is not changed, but UID for the removed packages is no longer exempted.
+        assertEquals(Arrays.asList(PKGS), vpn.getAppExclusionList(TEST_VPN_PKG));
+        assertEquals(newUidRanges, vpn.mNetworkCapabilities.getUids());
+        ArgumentCaptor<NetworkCapabilities> ncCaptor =
+                ArgumentCaptor.forClass(NetworkCapabilities.class);
+        verify(mMockNetworkAgent).doSendNetworkCapabilities(ncCaptor.capture());
+        assertEquals(newUidRanges, ncCaptor.getValue().getUids());
+        verify(mConnectivityManager).setVpnDefaultForUids(eq(sessionKey), eq(newUidRanges));
+
+        reset(mMockNetworkAgent);
+
+        // Add the package back
+        newExcludedUids.add(PKG_UIDS[0]);
+        newUidRanges = makeVpnUidRangeSet(PRIMARY_USER.id, newExcludedUids);
+        sPackages.put(PKGS[0], PKG_UIDS[0]);
+        vpn.refreshPlatformVpnAppExclusionList();
+
+        // List in keystore is not changed and the uid list should be updated in the net cap.
+        assertEquals(Arrays.asList(PKGS), vpn.getAppExclusionList(TEST_VPN_PKG));
+        assertEquals(newUidRanges, vpn.mNetworkCapabilities.getUids());
+        verify(mMockNetworkAgent).doSendNetworkCapabilities(ncCaptor.capture());
+        assertEquals(newUidRanges, ncCaptor.getValue().getUids());
+
+        // The uidRange is the same as the original setAppExclusionList so this is the second call
+        verify(mConnectivityManager, times(2))
+                .setVpnDefaultForUids(eq(sessionKey), eq(newUidRanges));
+    }
+
+    private List<Range<Integer>> makeVpnUidRange(int userId, List<Integer> excludedAppIdList) {
+        final SortedSet<Integer> list = new TreeSet<>();
+
+        final int userBase = userId * UserHandle.PER_USER_RANGE;
+        for (int appId : excludedAppIdList) {
+            final int uid = UserHandle.getUid(userId, appId);
+            list.add(uid);
+            if (Process.isApplicationUid(uid)) {
+                list.add(Process.toSdkSandboxUid(uid)); // Add Sdk Sandbox UID
+            }
+        }
+
+        final int minUid = userBase;
+        final int maxUid = userBase + UserHandle.PER_USER_RANGE - 1;
+        final List<Range<Integer>> ranges = new ArrayList<>();
+
+        // Iterate the list to create the ranges between each uid.
+        int start = minUid;
+        for (int uid : list) {
+            if (uid == start) {
+                start++;
+            } else {
+                ranges.add(new Range<>(start, uid - 1));
+                start = uid + 1;
+            }
+        }
+
+        // Create the range between last uid and max uid.
+        if (start <= maxUid) {
+            ranges.add(new Range<>(start, maxUid));
+        }
+
+        return ranges;
+    }
+
+    private Set<Range<Integer>> makeVpnUidRangeSet(int userId, List<Integer> excludedAppIdList) {
+        return new ArraySet<>(makeVpnUidRange(userId, excludedAppIdList));
+    }
+
+    @Test
+    public void testSetAndGetAppExclusionListRestrictedUser() throws Exception {
+        final Vpn vpn = prepareVpnForVerifyAppExclusionList();
+
+        // Mock it to restricted profile
+        when(mUserManager.getUserInfo(anyInt())).thenReturn(RESTRICTED_PROFILE_A);
+
+        // Restricted users cannot configure VPNs
+        assertThrows(SecurityException.class,
+                () -> vpn.setAppExclusionList(TEST_VPN_PKG, new ArrayList<>()));
+
+        assertEquals(Arrays.asList(PKGS), vpn.getAppExclusionList(TEST_VPN_PKG));
+    }
+
+    @Test
+    public void testProvisionVpnProfilePreconsented() throws Exception {
+        final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+
+        checkProvisionVpnProfile(
+                vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+    }
+
+    @Test
+    public void testProvisionVpnProfileNotPreconsented() throws Exception {
+        final Vpn vpn = createVpn();
+
+        // Expect that both the ACTIVATE_VPN and ACTIVATE_PLATFORM_VPN were tried, but the caller
+        // had neither.
+        checkProvisionVpnProfile(vpn, false /* expectedResult */,
+                AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN, AppOpsManager.OPSTR_ACTIVATE_VPN);
+    }
+
+    @Test
+    public void testProvisionVpnProfileVpnServicePreconsented() throws Exception {
+        final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_VPN);
+
+        checkProvisionVpnProfile(vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_VPN);
+    }
+
+    @Test
+    public void testProvisionVpnProfileTooLarge() throws Exception {
+        final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+
+        final VpnProfile bigProfile = new VpnProfile("");
+        bigProfile.name = new String(new byte[Vpn.MAX_VPN_PROFILE_SIZE_BYTES + 1]);
+
+        try {
+            vpn.provisionVpnProfile(TEST_VPN_PKG, bigProfile);
+            fail("Expected IAE due to profile size");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testProvisionVpnProfileRestrictedUser() throws Exception {
+        final Vpn vpn =
+                createVpn(
+                        RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+
+        try {
+            vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile);
+            fail("Expected SecurityException due to restricted user");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    @Test
+    public void testDeleteVpnProfile() throws Exception {
+        final Vpn vpn = createVpn();
+
+        vpn.deleteVpnProfile(TEST_VPN_PKG);
+
+        verify(mVpnProfileStore)
+                .remove(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
+    }
+
+    @Test
+    public void testDeleteVpnProfileRestrictedUser() throws Exception {
+        final Vpn vpn =
+                createVpn(
+                        RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+
+        try {
+            vpn.deleteVpnProfile(TEST_VPN_PKG);
+            fail("Expected SecurityException due to restricted user");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    @Test
+    public void testGetVpnProfilePrivileged() throws Exception {
+        final Vpn vpn = createVpn();
+
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+                .thenReturn(new VpnProfile("").encode());
+
+        vpn.getVpnProfilePrivileged(TEST_VPN_PKG);
+
+        verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
+    }
+
+    private void verifyPlatformVpnIsActivated(String packageName) {
+        verify(mAppOps).noteOpNoThrow(
+                eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
+                eq(Process.myUid()),
+                eq(packageName),
+                eq(null) /* attributionTag */,
+                eq(null) /* message */);
+        verify(mAppOps).startOp(
+                eq(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER),
+                eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
+                eq(packageName),
+                eq(null) /* attributionTag */,
+                eq(null) /* message */);
+    }
+
+    private void verifyPlatformVpnIsDeactivated(String packageName) {
+        // Add a small delay to double confirm that finishOp is only called once.
+        verify(mAppOps, after(100)).finishOp(
+                eq(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER),
+                eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
+                eq(packageName),
+                eq(null) /* attributionTag */);
+    }
+
+    @Test
+    public void testStartVpnProfile() throws Exception {
+        final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+                .thenReturn(mVpnProfile.encode());
+
+        vpn.startVpnProfile(TEST_VPN_PKG);
+
+        verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
+        verifyPlatformVpnIsActivated(TEST_VPN_PKG);
+    }
+
+    @Test
+    public void testStartVpnProfileVpnServicePreconsented() throws Exception {
+        final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_VPN);
+
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+                .thenReturn(mVpnProfile.encode());
+
+        vpn.startVpnProfile(TEST_VPN_PKG);
+
+        // Verify that the ACTIVATE_VPN appop was checked, but no error was thrown.
+        verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(),
+                TEST_VPN_PKG, null /* attributionTag */, null /* message */);
+    }
+
+    @Test
+    public void testStartVpnProfileNotConsented() throws Exception {
+        final Vpn vpn = createVpn();
+
+        try {
+            vpn.startVpnProfile(TEST_VPN_PKG);
+            fail("Expected failure due to no user consent");
+        } catch (SecurityException expected) {
+        }
+
+        // Verify both appops were checked.
+        verify(mAppOps)
+                .noteOpNoThrow(
+                        eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
+                        eq(Process.myUid()),
+                        eq(TEST_VPN_PKG),
+                        eq(null) /* attributionTag */,
+                        eq(null) /* message */);
+        verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(),
+                TEST_VPN_PKG, null /* attributionTag */, null /* message */);
+
+        // Keystore should never have been accessed.
+        verify(mVpnProfileStore, never()).get(any());
+    }
+
+    @Test
+    public void testStartVpnProfileMissingProfile() throws Exception {
+        final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))).thenReturn(null);
+
+        try {
+            vpn.startVpnProfile(TEST_VPN_PKG);
+            fail("Expected failure due to missing profile");
+        } catch (IllegalArgumentException expected) {
+        }
+
+        verify(mVpnProfileStore).get(vpn.getProfileNameForPackage(TEST_VPN_PKG));
+        verify(mAppOps)
+                .noteOpNoThrow(
+                        eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
+                        eq(Process.myUid()),
+                        eq(TEST_VPN_PKG),
+                        eq(null) /* attributionTag */,
+                        eq(null) /* message */);
+    }
+
+    @Test
+    public void testStartVpnProfileRestrictedUser() throws Exception {
+        final Vpn vpn = createVpn(RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+
+        try {
+            vpn.startVpnProfile(TEST_VPN_PKG);
+            fail("Expected SecurityException due to restricted user");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    @Test
+    public void testStopVpnProfileRestrictedUser() throws Exception {
+        final Vpn vpn = createVpn(RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+
+        try {
+            vpn.stopVpnProfile(TEST_VPN_PKG);
+            fail("Expected SecurityException due to restricted user");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    @Test
+    public void testStartOpAndFinishOpWillBeCalledWhenPlatformVpnIsOnAndOff() throws Exception {
+        final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+                .thenReturn(mVpnProfile.encode());
+        vpn.startVpnProfile(TEST_VPN_PKG);
+        verifyPlatformVpnIsActivated(TEST_VPN_PKG);
+        // Add a small delay to make sure that startOp is only called once.
+        verify(mAppOps, after(100).times(1)).startOp(
+                eq(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER),
+                eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
+                eq(TEST_VPN_PKG),
+                eq(null) /* attributionTag */,
+                eq(null) /* message */);
+        // Check that the startOp is not called with OPSTR_ESTABLISH_VPN_SERVICE.
+        verify(mAppOps, never()).startOp(
+                eq(AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE),
+                eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
+                eq(TEST_VPN_PKG),
+                eq(null) /* attributionTag */,
+                eq(null) /* message */);
+        vpn.stopVpnProfile(TEST_VPN_PKG);
+        verifyPlatformVpnIsDeactivated(TEST_VPN_PKG);
+    }
+
+    @Test
+    public void testStartOpWithSeamlessHandover() throws Exception {
+        // Create with SYSTEM_USER so that establish() will match the user ID when checking
+        // against Binder.getCallerUid
+        final Vpn vpn = createVpn(SYSTEM_USER, AppOpsManager.OPSTR_ACTIVATE_VPN);
+        assertTrue(vpn.prepare(TEST_VPN_PKG, null, VpnManager.TYPE_VPN_SERVICE));
+        final VpnConfig config = new VpnConfig();
+        config.user = "VpnTest";
+        config.addresses.add(new LinkAddress("192.0.2.2/32"));
+        config.mtu = 1450;
+        final ResolveInfo resolveInfo = new ResolveInfo();
+        final ServiceInfo serviceInfo = new ServiceInfo();
+        serviceInfo.permission = BIND_VPN_SERVICE;
+        resolveInfo.serviceInfo = serviceInfo;
+        when(mPackageManager.resolveService(any(), anyInt())).thenReturn(resolveInfo);
+        when(mContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true);
+        vpn.establish(config);
+        verify(mAppOps, times(1)).startOp(
+                eq(AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE),
+                eq(Process.myUid()),
+                eq(TEST_VPN_PKG),
+                eq(null) /* attributionTag */,
+                eq(null) /* message */);
+        // Call establish() twice with the same config, it should match seamless handover case and
+        // startOp() shouldn't be called again.
+        vpn.establish(config);
+        verify(mAppOps, times(1)).startOp(
+                eq(AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE),
+                eq(Process.myUid()),
+                eq(TEST_VPN_PKG),
+                eq(null) /* attributionTag */,
+                eq(null) /* message */);
+    }
+
+    private void verifyVpnManagerEvent(String sessionKey, String category, int errorClass,
+            int errorCode, String[] packageName, @NonNull VpnProfileState... profileState) {
+        final Context userContext =
+                mContext.createContextAsUser(UserHandle.of(PRIMARY_USER.id), 0 /* flags */);
+        final ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
+
+        final int verifyTimes = profileState.length;
+        verify(userContext, timeout(TEST_TIMEOUT_MS).times(verifyTimes))
+                .startService(intentArgumentCaptor.capture());
+
+        for (int i = 0; i < verifyTimes; i++) {
+            final Intent intent = intentArgumentCaptor.getAllValues().get(i);
+            assertEquals(packageName[i], intent.getPackage());
+            assertEquals(sessionKey, intent.getStringExtra(VpnManager.EXTRA_SESSION_KEY));
+            final Set<String> categories = intent.getCategories();
+            assertTrue(categories.contains(category));
+            assertEquals(1, categories.size());
+            assertEquals(errorClass,
+                    intent.getIntExtra(VpnManager.EXTRA_ERROR_CLASS, -1 /* defaultValue */));
+            assertEquals(errorCode,
+                    intent.getIntExtra(VpnManager.EXTRA_ERROR_CODE, -1 /* defaultValue */));
+            // CATEGORY_EVENT_DEACTIVATED_BY_USER & CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED won't
+            // send NetworkCapabilities & LinkProperties to VPN app.
+            // For ERROR_CODE_NETWORK_LOST, the NetworkCapabilities & LinkProperties of underlying
+            // network will be cleared. So the VPN app will receive null for those 2 extra values.
+            if (category.equals(VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER)
+                    || category.equals(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED)
+                    || errorCode == VpnManager.ERROR_CODE_NETWORK_LOST) {
+                assertNull(intent.getParcelableExtra(
+                        VpnManager.EXTRA_UNDERLYING_NETWORK_CAPABILITIES));
+                assertNull(intent.getParcelableExtra(VpnManager.EXTRA_UNDERLYING_LINK_PROPERTIES));
+            } else {
+                assertNotNull(intent.getParcelableExtra(
+                        VpnManager.EXTRA_UNDERLYING_NETWORK_CAPABILITIES));
+                assertNotNull(intent.getParcelableExtra(
+                        VpnManager.EXTRA_UNDERLYING_LINK_PROPERTIES));
+            }
+
+            assertEquals(profileState[i], intent.getParcelableExtra(
+                    VpnManager.EXTRA_VPN_PROFILE_STATE, VpnProfileState.class));
+        }
+        reset(userContext);
+    }
+
+    private void verifyDeactivatedByUser(String sessionKey, String[] packageName) {
+        // CATEGORY_EVENT_DEACTIVATED_BY_USER is not an error event, so both of errorClass and
+        // errorCode won't be set.
+        verifyVpnManagerEvent(sessionKey, VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER,
+                -1 /* errorClass */, -1 /* errorCode */, packageName,
+                // VPN NetworkAgnet does not switch to CONNECTED in the test, and the state is not
+                // important here. Verify that the state as it is, i.e. CONNECTING state.
+                new VpnProfileState(VpnProfileState.STATE_CONNECTING,
+                        sessionKey, false /* alwaysOn */, false /* lockdown */));
+    }
+
+    private void verifyAlwaysOnStateChanged(String[] packageName, VpnProfileState... profileState) {
+        verifyVpnManagerEvent(null /* sessionKey */,
+                VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED, -1 /* errorClass */,
+                -1 /* errorCode */, packageName, profileState);
+    }
+
+    @Test
+    public void testVpnManagerEventForUserDeactivated() throws Exception {
+        // For security reasons, Vpn#prepare() will check that oldPackage and newPackage are either
+        // null or the package of the caller. This test will call Vpn#prepare() to pretend the old
+        // VPN is replaced by a new one. But only Settings can change to some other packages, and
+        // this is checked with CONTROL_VPN so simulate holding CONTROL_VPN in order to pass the
+        // security checks.
+        doReturn(PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission(CONTROL_VPN);
+        final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+                .thenReturn(mVpnProfile.encode());
+
+        // Test the case that the user deactivates the vpn in vpn app.
+        final String sessionKey1 = vpn.startVpnProfile(TEST_VPN_PKG);
+        verifyPlatformVpnIsActivated(TEST_VPN_PKG);
+        vpn.stopVpnProfile(TEST_VPN_PKG);
+        verifyPlatformVpnIsDeactivated(TEST_VPN_PKG);
+        verifyPowerSaveTempWhitelistApp(TEST_VPN_PKG);
+        reset(mDeviceIdleInternal);
+        verifyDeactivatedByUser(sessionKey1, new String[] {TEST_VPN_PKG});
+        reset(mAppOps);
+
+        // Test the case that the user chooses another vpn and the original one is replaced.
+        final String sessionKey2 = vpn.startVpnProfile(TEST_VPN_PKG);
+        verifyPlatformVpnIsActivated(TEST_VPN_PKG);
+        vpn.prepare(TEST_VPN_PKG, "com.new.vpn" /* newPackage */, TYPE_VPN_PLATFORM);
+        verifyPlatformVpnIsDeactivated(TEST_VPN_PKG);
+        verifyPowerSaveTempWhitelistApp(TEST_VPN_PKG);
+        reset(mDeviceIdleInternal);
+        verifyDeactivatedByUser(sessionKey2, new String[] {TEST_VPN_PKG});
+    }
+
+    @Test
+    public void testVpnManagerEventForAlwaysOnChanged() throws Exception {
+        // Calling setAlwaysOnPackage() needs to hold CONTROL_VPN.
+        doReturn(PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission(CONTROL_VPN);
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+        // Enable VPN always-on for PKGS[1].
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false /* lockdown */,
+                null /* lockdownAllowlist */));
+        verifyPowerSaveTempWhitelistApp(PKGS[1]);
+        reset(mDeviceIdleInternal);
+        verifyAlwaysOnStateChanged(new String[] {PKGS[1]},
+                new VpnProfileState(VpnProfileState.STATE_DISCONNECTED,
+                        null /* sessionKey */, true /* alwaysOn */, false /* lockdown */));
+
+        // Enable VPN lockdown for PKGS[1].
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true /* lockdown */,
+                null /* lockdownAllowlist */));
+        verifyPowerSaveTempWhitelistApp(PKGS[1]);
+        reset(mDeviceIdleInternal);
+        verifyAlwaysOnStateChanged(new String[] {PKGS[1]},
+                new VpnProfileState(VpnProfileState.STATE_DISCONNECTED,
+                        null /* sessionKey */, true /* alwaysOn */, true /* lockdown */));
+
+        // Disable VPN lockdown for PKGS[1].
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false /* lockdown */,
+                null /* lockdownAllowlist */));
+        verifyPowerSaveTempWhitelistApp(PKGS[1]);
+        reset(mDeviceIdleInternal);
+        verifyAlwaysOnStateChanged(new String[] {PKGS[1]},
+                new VpnProfileState(VpnProfileState.STATE_DISCONNECTED,
+                        null /* sessionKey */, true /* alwaysOn */, false /* lockdown */));
+
+        // Disable VPN always-on.
+        assertTrue(vpn.setAlwaysOnPackage(null, false /* lockdown */,
+                null /* lockdownAllowlist */));
+        verifyPowerSaveTempWhitelistApp(PKGS[1]);
+        reset(mDeviceIdleInternal);
+        verifyAlwaysOnStateChanged(new String[] {PKGS[1]},
+                new VpnProfileState(VpnProfileState.STATE_DISCONNECTED,
+                        null /* sessionKey */, false /* alwaysOn */, false /* lockdown */));
+
+        // Enable VPN always-on for PKGS[1] again.
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false /* lockdown */,
+                null /* lockdownAllowlist */));
+        verifyPowerSaveTempWhitelistApp(PKGS[1]);
+        reset(mDeviceIdleInternal);
+        verifyAlwaysOnStateChanged(new String[] {PKGS[1]},
+                new VpnProfileState(VpnProfileState.STATE_DISCONNECTED,
+                        null /* sessionKey */, true /* alwaysOn */, false /* lockdown */));
+
+        // Enable VPN always-on for PKGS[2].
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[2], false /* lockdown */,
+                null /* lockdownAllowlist */));
+        verifyPowerSaveTempWhitelistApp(PKGS[2]);
+        reset(mDeviceIdleInternal);
+        // PKGS[1] is replaced with PKGS[2].
+        // Pass 2 VpnProfileState objects to verifyVpnManagerEvent(), the first one is sent to
+        // PKGS[1] to notify PKGS[1] that the VPN always-on is disabled, the second one is sent to
+        // PKGS[2] to notify PKGS[2] that the VPN always-on is enabled.
+        verifyAlwaysOnStateChanged(new String[] {PKGS[1], PKGS[2]},
+                new VpnProfileState(VpnProfileState.STATE_DISCONNECTED,
+                        null /* sessionKey */, false /* alwaysOn */, false /* lockdown */),
+                new VpnProfileState(VpnProfileState.STATE_DISCONNECTED,
+                        null /* sessionKey */, true /* alwaysOn */, false /* lockdown */));
+    }
+
+    @Test
+    public void testReconnectVpnManagerVpnWithAlwaysOnEnabled() throws Exception {
+        final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+                .thenReturn(mVpnProfile.encode());
+        vpn.startVpnProfile(TEST_VPN_PKG);
+        verifyPlatformVpnIsActivated(TEST_VPN_PKG);
+
+        // Enable VPN always-on for TEST_VPN_PKG.
+        assertTrue(vpn.setAlwaysOnPackage(TEST_VPN_PKG, false /* lockdown */,
+                null /* lockdownAllowlist */));
+
+        // Reset to verify next startVpnProfile.
+        reset(mAppOps);
+
+        vpn.stopVpnProfile(TEST_VPN_PKG);
+
+        // Reconnect the vpn with different package will cause exception.
+        assertThrows(SecurityException.class, () -> vpn.startVpnProfile(PKGS[0]));
+
+        // Reconnect the vpn again with the vpn always on package w/o exception.
+        vpn.startVpnProfile(TEST_VPN_PKG);
+        verifyPlatformVpnIsActivated(TEST_VPN_PKG);
+    }
+
+    @Test
+    public void testLockdown_enableDisableWhileConnected() throws Exception {
+        final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
+                createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
+
+        final InOrder order = inOrder(mTestDeps);
+        order.verify(mTestDeps, timeout(TIMEOUT_CROSSTHREAD_MS))
+                .newNetworkAgent(any(), any(), any(), any(), any(), any(),
+                        argThat(config -> config.allowBypass), any(), any());
+
+        // Make VPN lockdown.
+        assertTrue(vpnSnapShot.vpn.setAlwaysOnPackage(TEST_VPN_PKG, true /* lockdown */,
+                null /* lockdownAllowlist */));
+
+        order.verify(mTestDeps, timeout(TIMEOUT_CROSSTHREAD_MS))
+                .newNetworkAgent(any(), any(), any(), any(), any(), any(),
+                argThat(config -> !config.allowBypass), any(), any());
+
+        // Disable lockdown.
+        assertTrue(vpnSnapShot.vpn.setAlwaysOnPackage(TEST_VPN_PKG, false /* lockdown */,
+                null /* lockdownAllowlist */));
+
+        order.verify(mTestDeps, timeout(TIMEOUT_CROSSTHREAD_MS))
+                .newNetworkAgent(any(), any(), any(), any(), any(), any(),
+                        argThat(config -> config.allowBypass), any(), any());
+    }
+
+    @Test
+    public void testSetPackageAuthorizationVpnService() throws Exception {
+        final Vpn vpn = createVpn();
+
+        assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_SERVICE));
+        verify(mAppOps)
+                .setMode(
+                        eq(AppOpsManager.OPSTR_ACTIVATE_VPN),
+                        eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
+                        eq(TEST_VPN_PKG),
+                        eq(AppOpsManager.MODE_ALLOWED));
+    }
+
+    @Test
+    public void testSetPackageAuthorizationPlatformVpn() throws Exception {
+        final Vpn vpn = createVpn();
+
+        assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, TYPE_VPN_PLATFORM));
+        verify(mAppOps)
+                .setMode(
+                        eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
+                        eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
+                        eq(TEST_VPN_PKG),
+                        eq(AppOpsManager.MODE_ALLOWED));
+    }
+
+    @Test
+    public void testSetPackageAuthorizationRevokeAuthorization() throws Exception {
+        final Vpn vpn = createVpn();
+
+        assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_NONE));
+        verify(mAppOps)
+                .setMode(
+                        eq(AppOpsManager.OPSTR_ACTIVATE_VPN),
+                        eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
+                        eq(TEST_VPN_PKG),
+                        eq(AppOpsManager.MODE_IGNORED));
+        verify(mAppOps)
+                .setMode(
+                        eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
+                        eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
+                        eq(TEST_VPN_PKG),
+                        eq(AppOpsManager.MODE_IGNORED));
+    }
+
+    private NetworkCallback triggerOnAvailableAndGetCallback() throws Exception {
+        return triggerOnAvailableAndGetCallback(new NetworkCapabilities.Builder().build());
+    }
+
+    private NetworkCallback triggerOnAvailableAndGetCallback(
+            @NonNull final NetworkCapabilities caps) throws Exception {
+        final ArgumentCaptor<NetworkCallback> networkCallbackCaptor =
+                ArgumentCaptor.forClass(NetworkCallback.class);
+        verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS))
+                .registerSystemDefaultNetworkCallback(networkCallbackCaptor.capture(), any());
+
+        // onAvailable() will trigger onDefaultNetworkChanged(), so NetdUtils#setInterfaceUp will be
+        // invoked. Set the return value of INetd#interfaceGetCfg to prevent NullPointerException.
+        final InterfaceConfigurationParcel config = new InterfaceConfigurationParcel();
+        config.flags = new String[] {IF_STATE_DOWN};
+        when(mNetd.interfaceGetCfg(anyString())).thenReturn(config);
+        final NetworkCallback cb = networkCallbackCaptor.getValue();
+        cb.onAvailable(TEST_NETWORK);
+        // Trigger onCapabilitiesChanged() and onLinkPropertiesChanged() so the test can verify that
+        // if NetworkCapabilities and LinkProperties of underlying network will be sent/cleared or
+        // not.
+        // See verifyVpnManagerEvent().
+        cb.onCapabilitiesChanged(TEST_NETWORK, caps);
+        cb.onLinkPropertiesChanged(TEST_NETWORK, new LinkProperties());
+        return cb;
+    }
+
+    private void verifyInterfaceSetCfgWithFlags(String flag) throws Exception {
+        // Add a timeout for waiting for interfaceSetCfg to be called.
+        verify(mNetd, timeout(TEST_TIMEOUT_MS)).interfaceSetCfg(argThat(
+                config -> Arrays.asList(config.flags).contains(flag)));
+    }
+
+    private void doTestPlatformVpnWithException(IkeException exception,
+            String category, int errorType, int errorCode) throws Exception {
+        final ArgumentCaptor<IkeSessionCallback> captor =
+                ArgumentCaptor.forClass(IkeSessionCallback.class);
+
+        final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+                .thenReturn(mVpnProfile.encode());
+
+        doReturn(new NetworkCapabilities()).when(mConnectivityManager)
+                .getRedactedNetworkCapabilitiesForPackage(any(), anyInt(), anyString());
+        doReturn(new LinkProperties()).when(mConnectivityManager)
+                .getRedactedLinkPropertiesForPackage(any(), anyInt(), anyString());
+
+        final String sessionKey = vpn.startVpnProfile(TEST_VPN_PKG);
+        final Set<Range<Integer>> uidRanges = rangeSet(PRIMARY_USER_RANGE);
+        // This is triggered by Ikev2VpnRunner constructor.
+        verify(mConnectivityManager, times(1)).setVpnDefaultForUids(eq(sessionKey), eq(uidRanges));
+        final NetworkCallback cb = triggerOnAvailableAndGetCallback();
+
+        verifyInterfaceSetCfgWithFlags(IF_STATE_UP);
+
+        // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
+        // state
+        verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS))
+                .createIkeSession(any(), any(), any(), any(), captor.capture(), any());
+        // This is triggered by Vpn#startOrMigrateIkeSession().
+        verify(mConnectivityManager, times(2)).setVpnDefaultForUids(eq(sessionKey), eq(uidRanges));
+        reset(mIkev2SessionCreator);
+        // For network lost case, the process should be triggered by calling onLost(), which is the
+        // same process with the real case.
+        if (errorCode == VpnManager.ERROR_CODE_NETWORK_LOST) {
+            cb.onLost(TEST_NETWORK);
+            verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any());
+        } else {
+            final IkeSessionCallback ikeCb = captor.getValue();
+            mExecutor.execute(() -> ikeCb.onClosedWithException(exception));
+        }
+
+        verifyPowerSaveTempWhitelistApp(TEST_VPN_PKG);
+        reset(mDeviceIdleInternal);
+        verifyVpnManagerEvent(sessionKey, category, errorType, errorCode,
+                // VPN NetworkAgnet does not switch to CONNECTED in the test, and the state is not
+                // important here. Verify that the state as it is, i.e. CONNECTING state.
+                new String[] {TEST_VPN_PKG}, new VpnProfileState(VpnProfileState.STATE_CONNECTING,
+                        sessionKey, false /* alwaysOn */, false /* lockdown */));
+        if (errorType == VpnManager.ERROR_CLASS_NOT_RECOVERABLE) {
+            verify(mConnectivityManager).setVpnDefaultForUids(eq(sessionKey),
+                    eq(Collections.EMPTY_LIST));
+            verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS))
+                    .unregisterNetworkCallback(eq(cb));
+        } else if (errorType == VpnManager.ERROR_CLASS_RECOVERABLE
+                // Vpn won't retry when there is no usable underlying network.
+                && errorCode != VpnManager.ERROR_CODE_NETWORK_LOST) {
+            int retryIndex = 0;
+            // First failure occurred above.
+            final IkeSessionCallback retryCb = verifyRetryAndGetNewIkeCb(retryIndex++);
+            // Trigger 2 more failures to let the retry delay increase to 5s.
+            mExecutor.execute(() -> retryCb.onClosedWithException(exception));
+            final IkeSessionCallback retryCb2 = verifyRetryAndGetNewIkeCb(retryIndex++);
+            mExecutor.execute(() -> retryCb2.onClosedWithException(exception));
+            final IkeSessionCallback retryCb3 = verifyRetryAndGetNewIkeCb(retryIndex++);
+
+            // setVpnDefaultForUids may be called again but the uidRanges should not change.
+            verify(mConnectivityManager, atLeast(2)).setVpnDefaultForUids(eq(sessionKey),
+                    mUidRangesCaptor.capture());
+            final List<Collection<Range<Integer>>> capturedUidRanges =
+                    mUidRangesCaptor.getAllValues();
+            for (int i = 2; i < capturedUidRanges.size(); i++) {
+                // Assert equals no order.
+                assertTrue(
+                        "uid ranges should not be modified. Expected: " + uidRanges
+                                + ", actual: " + capturedUidRanges.get(i),
+                        capturedUidRanges.get(i).containsAll(uidRanges)
+                                && capturedUidRanges.get(i).size() == uidRanges.size());
+            }
+
+            // A fourth failure will cause the retry delay to be greater than 5s.
+            mExecutor.execute(() -> retryCb3.onClosedWithException(exception));
+            verifyRetryAndGetNewIkeCb(retryIndex++);
+
+            // The VPN network preference will be cleared when the retry delay is greater than 5s.
+            verify(mConnectivityManager).setVpnDefaultForUids(eq(sessionKey),
+                    eq(Collections.EMPTY_LIST));
+        }
+    }
+
+    private IkeSessionCallback verifyRetryAndGetNewIkeCb(int retryIndex) {
+        final ArgumentCaptor<IkeSessionCallback> ikeCbCaptor =
+                ArgumentCaptor.forClass(IkeSessionCallback.class);
+
+        // Verify retry is scheduled
+        final long expectedDelayMs = mTestDeps.getNextRetryDelayMs(retryIndex);
+        verify(mExecutor, timeout(TEST_TIMEOUT_MS)).schedule(any(Runnable.class),
+                eq(expectedDelayMs), eq(TimeUnit.MILLISECONDS));
+
+        verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS + expectedDelayMs))
+                .createIkeSession(any(), any(), any(), any(), ikeCbCaptor.capture(), any());
+
+        // Forget the mIkev2SessionCreator#createIkeSession call and mExecutor#schedule call
+        // for the next retry verification
+        resetIkev2SessionCreator(mIkeSessionWrapper);
+
+        return ikeCbCaptor.getValue();
+    }
+
+    @Test
+    public void testStartPlatformVpnAuthenticationFailed() throws Exception {
+        final IkeProtocolException exception = mock(IkeProtocolException.class);
+        final int errorCode = IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED;
+        when(exception.getErrorType()).thenReturn(errorCode);
+        doTestPlatformVpnWithException(exception,
+                VpnManager.CATEGORY_EVENT_IKE_ERROR, VpnManager.ERROR_CLASS_NOT_RECOVERABLE,
+                errorCode);
+    }
+
+    @Test
+    public void testStartPlatformVpnFailedWithRecoverableError() throws Exception {
+        final IkeProtocolException exception = mock(IkeProtocolException.class);
+        final int errorCode = IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE;
+        when(exception.getErrorType()).thenReturn(errorCode);
+        doTestPlatformVpnWithException(exception,
+                VpnManager.CATEGORY_EVENT_IKE_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE, errorCode);
+    }
+
+    @Test
+    public void testStartPlatformVpnFailedWithUnknownHostException() throws Exception {
+        final IkeNonProtocolException exception = mock(IkeNonProtocolException.class);
+        final UnknownHostException unknownHostException = new UnknownHostException();
+        final int errorCode = VpnManager.ERROR_CODE_NETWORK_UNKNOWN_HOST;
+        when(exception.getCause()).thenReturn(unknownHostException);
+        doTestPlatformVpnWithException(exception,
+                VpnManager.CATEGORY_EVENT_NETWORK_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE,
+                errorCode);
+    }
+
+    @Test
+    public void testStartPlatformVpnFailedWithIkeTimeoutException() throws Exception {
+        final IkeNonProtocolException exception = mock(IkeNonProtocolException.class);
+        final IkeTimeoutException ikeTimeoutException =
+                new IkeTimeoutException("IkeTimeoutException");
+        final int errorCode = VpnManager.ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT;
+        when(exception.getCause()).thenReturn(ikeTimeoutException);
+        doTestPlatformVpnWithException(exception,
+                VpnManager.CATEGORY_EVENT_NETWORK_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE,
+                errorCode);
+    }
+
+    @Test
+    public void testStartPlatformVpnFailedWithIkeNetworkLostException() throws Exception {
+        final IkeNetworkLostException exception = new IkeNetworkLostException(
+                new Network(100));
+        doTestPlatformVpnWithException(exception,
+                VpnManager.CATEGORY_EVENT_NETWORK_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE,
+                VpnManager.ERROR_CODE_NETWORK_LOST);
+    }
+
+    @Test
+    public void testStartPlatformVpnFailedWithIOException() throws Exception {
+        final IkeNonProtocolException exception = mock(IkeNonProtocolException.class);
+        final IOException ioException = new IOException();
+        final int errorCode = VpnManager.ERROR_CODE_NETWORK_IO;
+        when(exception.getCause()).thenReturn(ioException);
+        doTestPlatformVpnWithException(exception,
+                VpnManager.CATEGORY_EVENT_NETWORK_ERROR, VpnManager.ERROR_CLASS_RECOVERABLE,
+                errorCode);
+    }
+
+    @Test
+    public void testStartPlatformVpnIllegalArgumentExceptionInSetup() throws Exception {
+        when(mIkev2SessionCreator.createIkeSession(any(), any(), any(), any(), any(), any()))
+                .thenThrow(new IllegalArgumentException());
+        final Vpn vpn = startLegacyVpn(createVpn(PRIMARY_USER.id), mVpnProfile);
+        final NetworkCallback cb = triggerOnAvailableAndGetCallback();
+
+        verifyInterfaceSetCfgWithFlags(IF_STATE_UP);
+
+        // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
+        // state
+        verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
+        assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
+    }
+
+    @Test
+    public void testVpnManagerEventWillNotBeSentToSettingsVpn() throws Exception {
+        startLegacyVpn(createVpn(PRIMARY_USER.id), mVpnProfile);
+        triggerOnAvailableAndGetCallback();
+
+        verifyInterfaceSetCfgWithFlags(IF_STATE_UP);
+
+        final IkeNonProtocolException exception = mock(IkeNonProtocolException.class);
+        final IkeTimeoutException ikeTimeoutException =
+                new IkeTimeoutException("IkeTimeoutException");
+        when(exception.getCause()).thenReturn(ikeTimeoutException);
+
+        final ArgumentCaptor<IkeSessionCallback> captor =
+                ArgumentCaptor.forClass(IkeSessionCallback.class);
+        verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS))
+                .createIkeSession(any(), any(), any(), any(), captor.capture(), any());
+        final IkeSessionCallback ikeCb = captor.getValue();
+        ikeCb.onClosedWithException(exception);
+
+        final Context userContext =
+                mContext.createContextAsUser(UserHandle.of(PRIMARY_USER.id), 0 /* flags */);
+        verify(userContext, never()).startService(any());
+    }
+
+    private void setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled) {
+        assertTrue(vpn.setAlwaysOnPackage(TEST_VPN_PKG, lockdownEnabled, null));
+
+        verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
+        verify(mAppOps).setMode(
+                eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), eq(uid), eq(TEST_VPN_PKG),
+                eq(AppOpsManager.MODE_ALLOWED));
+
+        verify(mSystemServices).settingsSecurePutStringForUser(
+                eq(Settings.Secure.ALWAYS_ON_VPN_APP), eq(TEST_VPN_PKG), eq(PRIMARY_USER.id));
+        verify(mSystemServices).settingsSecurePutIntForUser(
+                eq(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN), eq(lockdownEnabled ? 1 : 0),
+                eq(PRIMARY_USER.id));
+        verify(mSystemServices).settingsSecurePutStringForUser(
+                eq(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST), eq(""), eq(PRIMARY_USER.id));
+    }
+
+    @Test
+    public void testSetAndStartAlwaysOnVpn() throws Exception {
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+        setMockedUsers(PRIMARY_USER);
+
+        // UID checks must return a different UID; otherwise it'll be treated as already prepared.
+        final int uid = Process.myUid() + 1;
+        when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt()))
+                .thenReturn(uid);
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+                .thenReturn(mVpnProfile.encode());
+
+        setAndVerifyAlwaysOnPackage(vpn, uid, false);
+        assertTrue(vpn.startAlwaysOnVpn());
+
+        // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
+        // a subsequent CL.
+    }
+
+    private Vpn startLegacyVpn(final Vpn vpn, final VpnProfile vpnProfile) throws Exception {
+        setMockedUsers(PRIMARY_USER);
+        vpn.startLegacyVpn(vpnProfile);
+        return vpn;
+    }
+
+    private IkeSessionConnectionInfo createIkeConnectInfo() {
+        return new IkeSessionConnectionInfo(TEST_VPN_CLIENT_IP, TEST_VPN_SERVER_IP, TEST_NETWORK);
+    }
+
+    private IkeSessionConnectionInfo createIkeConnectInfo_2() {
+        return new IkeSessionConnectionInfo(
+                TEST_VPN_CLIENT_IP_2, TEST_VPN_SERVER_IP_2, TEST_NETWORK_2);
+    }
+
+    private IkeSessionConfiguration createIkeConfig(
+            IkeSessionConnectionInfo ikeConnectInfo, boolean isMobikeEnabled) {
+        final IkeSessionConfiguration.Builder builder =
+                new IkeSessionConfiguration.Builder(ikeConnectInfo);
+
+        if (isMobikeEnabled) {
+            builder.addIkeExtension(EXTENSION_TYPE_MOBIKE);
+        }
+
+        return builder.build();
+    }
+
+    private ChildSessionConfiguration createChildConfig() {
+        return new ChildSessionConfiguration.Builder(
+                        Arrays.asList(IN_TS, IN_TS6), Arrays.asList(OUT_TS, OUT_TS6))
+                .addInternalAddress(new LinkAddress(TEST_VPN_INTERNAL_IP, IP4_PREFIX_LEN))
+                .addInternalAddress(new LinkAddress(TEST_VPN_INTERNAL_IP6, IP6_PREFIX_LEN))
+                .addInternalDnsServer(TEST_VPN_INTERNAL_DNS)
+                .addInternalDnsServer(TEST_VPN_INTERNAL_DNS6)
+                .build();
+    }
+
+    private IpSecTransform createIpSecTransform() {
+        return new IpSecTransform(mContext, new IpSecConfig());
+    }
+
+    private void verifyApplyTunnelModeTransforms(int expectedTimes) throws Exception {
+        verify(mIpSecService, times(expectedTimes)).applyTunnelModeTransform(
+                eq(TEST_TUNNEL_RESOURCE_ID), eq(IpSecManager.DIRECTION_IN),
+                anyInt(), anyString());
+        verify(mIpSecService, times(expectedTimes)).applyTunnelModeTransform(
+                eq(TEST_TUNNEL_RESOURCE_ID), eq(IpSecManager.DIRECTION_OUT),
+                anyInt(), anyString());
+    }
+
+    private Pair<IkeSessionCallback, ChildSessionCallback> verifyCreateIkeAndCaptureCbs()
+            throws Exception {
+        final ArgumentCaptor<IkeSessionCallback> ikeCbCaptor =
+                ArgumentCaptor.forClass(IkeSessionCallback.class);
+        final ArgumentCaptor<ChildSessionCallback> childCbCaptor =
+                ArgumentCaptor.forClass(ChildSessionCallback.class);
+
+        verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS)).createIkeSession(
+                any(), any(), any(), any(), ikeCbCaptor.capture(), childCbCaptor.capture());
+
+        return new Pair<>(ikeCbCaptor.getValue(), childCbCaptor.getValue());
+    }
+
+    private static class PlatformVpnSnapshot {
+        public final Vpn vpn;
+        public final NetworkCallback nwCb;
+        public final IkeSessionCallback ikeCb;
+        public final ChildSessionCallback childCb;
+
+        PlatformVpnSnapshot(Vpn vpn, NetworkCallback nwCb,
+                IkeSessionCallback ikeCb, ChildSessionCallback childCb) {
+            this.vpn = vpn;
+            this.nwCb = nwCb;
+            this.ikeCb = ikeCb;
+            this.childCb = childCb;
+        }
+    }
+
+    private PlatformVpnSnapshot verifySetupPlatformVpn(IkeSessionConfiguration ikeConfig)
+            throws Exception {
+        return verifySetupPlatformVpn(ikeConfig, true);
+    }
+
+    private PlatformVpnSnapshot verifySetupPlatformVpn(
+            IkeSessionConfiguration ikeConfig, boolean mtuSupportsIpv6) throws Exception {
+        return verifySetupPlatformVpn(mVpnProfile, ikeConfig, mtuSupportsIpv6);
+    }
+
+    private PlatformVpnSnapshot verifySetupPlatformVpn(VpnProfile vpnProfile,
+            IkeSessionConfiguration ikeConfig, boolean mtuSupportsIpv6) throws Exception {
+        return verifySetupPlatformVpn(vpnProfile, ikeConfig,
+                new NetworkCapabilities.Builder().build() /* underlying network caps */,
+                mtuSupportsIpv6, false /* areLongLivedTcpConnectionsExpensive */);
+    }
+
+    private PlatformVpnSnapshot verifySetupPlatformVpn(VpnProfile vpnProfile,
+            IkeSessionConfiguration ikeConfig,
+            @NonNull final NetworkCapabilities underlyingNetworkCaps,
+            boolean mtuSupportsIpv6,
+            boolean areLongLivedTcpConnectionsExpensive) throws Exception {
+        if (!mtuSupportsIpv6) {
+            doReturn(IPV6_MIN_MTU - 1).when(mTestDeps).calculateVpnMtu(any(), anyInt(), anyInt(),
+                    anyBoolean());
+        }
+
+        doReturn(mMockNetworkAgent).when(mTestDeps)
+                .newNetworkAgent(
+                        any(), any(), anyString(), any(), any(), any(), any(), any(), any());
+        doReturn(TEST_NETWORK).when(mMockNetworkAgent).getNetwork();
+
+        final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+                .thenReturn(vpnProfile.encode());
+
+        final String sessionKey = vpn.startVpnProfile(TEST_VPN_PKG);
+        final Set<Range<Integer>> uidRanges = Collections.singleton(PRIMARY_USER_RANGE);
+        verify(mConnectivityManager).setVpnDefaultForUids(eq(sessionKey), eq(uidRanges));
+        final NetworkCallback nwCb = triggerOnAvailableAndGetCallback(underlyingNetworkCaps);
+        // There are 4 interactions with the executor.
+        // - Network available
+        // - LP change
+        // - NC change
+        // - schedule() calls in scheduleStartIkeSession()
+        // The first 3 calls are triggered from Executor.execute(). The execute() will also call to
+        // schedule() with 0 delay. Verify the exact interaction here so that it won't cause flakes
+        // in the follow-up flow.
+        verify(mExecutor, timeout(TEST_TIMEOUT_MS).times(4))
+                .schedule(any(Runnable.class), anyLong(), any());
+        reset(mExecutor);
+
+        // Mock the setup procedure by firing callbacks
+        final Pair<IkeSessionCallback, ChildSessionCallback> cbPair =
+                verifyCreateIkeAndCaptureCbs();
+        final IkeSessionCallback ikeCb = cbPair.first;
+        final ChildSessionCallback childCb = cbPair.second;
+
+        ikeCb.onOpened(ikeConfig);
+        childCb.onIpSecTransformCreated(createIpSecTransform(), IpSecManager.DIRECTION_IN);
+        childCb.onIpSecTransformCreated(createIpSecTransform(), IpSecManager.DIRECTION_OUT);
+        childCb.onOpened(createChildConfig());
+
+        // Verification VPN setup
+        verifyApplyTunnelModeTransforms(1);
+
+        ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class);
+        ArgumentCaptor<NetworkCapabilities> ncCaptor =
+                ArgumentCaptor.forClass(NetworkCapabilities.class);
+        ArgumentCaptor<NetworkAgentConfig> nacCaptor =
+                ArgumentCaptor.forClass(NetworkAgentConfig.class);
+        verify(mTestDeps).newNetworkAgent(
+                any(), any(), anyString(), ncCaptor.capture(), lpCaptor.capture(),
+                any(), nacCaptor.capture(), any(), any());
+        verify(mIkeSessionWrapper).setUnderpinnedNetwork(TEST_NETWORK);
+        // Check LinkProperties
+        final LinkProperties lp = lpCaptor.getValue();
+        final List<RouteInfo> expectedRoutes =
+                new ArrayList<>(
+                        Arrays.asList(
+                                new RouteInfo(
+                                        new IpPrefix(Inet4Address.ANY, 0),
+                                        null /* gateway */,
+                                        TEST_IFACE_NAME,
+                                        RouteInfo.RTN_UNICAST)));
+        final List<LinkAddress> expectedAddresses =
+                new ArrayList<>(
+                        Arrays.asList(new LinkAddress(TEST_VPN_INTERNAL_IP, IP4_PREFIX_LEN)));
+        final List<InetAddress> expectedDns = new ArrayList<>(Arrays.asList(TEST_VPN_INTERNAL_DNS));
+
+        if (mtuSupportsIpv6) {
+            expectedRoutes.add(
+                    new RouteInfo(
+                            new IpPrefix(Inet6Address.ANY, 0),
+                            null /* gateway */,
+                            TEST_IFACE_NAME,
+                            RouteInfo.RTN_UNICAST));
+            expectedAddresses.add(new LinkAddress(TEST_VPN_INTERNAL_IP6, IP6_PREFIX_LEN));
+            expectedDns.add(TEST_VPN_INTERNAL_DNS6);
+        } else {
+            expectedRoutes.add(
+                    new RouteInfo(
+                            new IpPrefix(Inet6Address.ANY, 0),
+                            null /* gateway */,
+                            TEST_IFACE_NAME,
+                            RTN_UNREACHABLE));
+        }
+
+        assertEquals(expectedRoutes, lp.getRoutes());
+        assertEquals(expectedAddresses, lp.getLinkAddresses());
+        assertEquals(expectedDns, lp.getDnsServers());
+
+        // Check NetworkCapabilities
+        assertEquals(Arrays.asList(TEST_NETWORK), ncCaptor.getValue().getUnderlyingNetworks());
+
+        // Check if allowBypass is set or not.
+        assertTrue(nacCaptor.getValue().isBypassableVpn());
+        // Check if extra info for VPN is set.
+        assertTrue(nacCaptor.getValue().getLegacyExtraInfo().contains(TEST_VPN_PKG));
+        final VpnTransportInfo info = (VpnTransportInfo) ncCaptor.getValue().getTransportInfo();
+        assertTrue(info.isBypassable());
+        assertEquals(areLongLivedTcpConnectionsExpensive,
+                info.areLongLivedTcpConnectionsExpensive());
+        return new PlatformVpnSnapshot(vpn, nwCb, ikeCb, childCb);
+    }
+
+    @Test
+    public void testStartPlatformVpn() throws Exception {
+        final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
+                createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
+        vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
+        verify(mConnectivityManager).setVpnDefaultForUids(anyString(), eq(Collections.EMPTY_LIST));
+    }
+
+    @Test
+    public void testMigrateIkeSession_FromIkeTunnConnParams_AutoTimerNoTimer() throws Exception {
+        doTestMigrateIkeSession_FromIkeTunnConnParams(
+                false /* isAutomaticIpVersionSelectionEnabled */,
+                true /* isAutomaticNattKeepaliveTimerEnabled */,
+                TEST_KEEPALIVE_TIMEOUT_UNSET /* keepaliveInProfile */,
+                ESP_IP_VERSION_AUTO /* ipVersionInProfile */,
+                ESP_ENCAP_TYPE_AUTO /* encapTypeInProfile */);
+    }
+
+    @Test
+    public void testMigrateIkeSession_FromIkeTunnConnParams_AutoTimerTimerSet() throws Exception {
+        doTestMigrateIkeSession_FromIkeTunnConnParams(
+                false /* isAutomaticIpVersionSelectionEnabled */,
+                true /* isAutomaticNattKeepaliveTimerEnabled */,
+                TEST_KEEPALIVE_TIMER /* keepaliveInProfile */,
+                ESP_IP_VERSION_AUTO /* ipVersionInProfile */,
+                ESP_ENCAP_TYPE_AUTO /* encapTypeInProfile */);
+    }
+
+    @Test
+    public void testMigrateIkeSession_FromIkeTunnConnParams_AutoIp() throws Exception {
+        doTestMigrateIkeSession_FromIkeTunnConnParams(
+                true /* isAutomaticIpVersionSelectionEnabled */,
+                false /* isAutomaticNattKeepaliveTimerEnabled */,
+                TEST_KEEPALIVE_TIMEOUT_UNSET /* keepaliveInProfile */,
+                ESP_IP_VERSION_AUTO /* ipVersionInProfile */,
+                ESP_ENCAP_TYPE_AUTO /* encapTypeInProfile */);
+    }
+
+    @Test
+    public void testMigrateIkeSession_FromIkeTunnConnParams_AssignedIpProtocol() throws Exception {
+        doTestMigrateIkeSession_FromIkeTunnConnParams(
+                false /* isAutomaticIpVersionSelectionEnabled */,
+                false /* isAutomaticNattKeepaliveTimerEnabled */,
+                TEST_KEEPALIVE_TIMEOUT_UNSET /* keepaliveInProfile */,
+                ESP_IP_VERSION_IPV4 /* ipVersionInProfile */,
+                ESP_ENCAP_TYPE_UDP /* encapTypeInProfile */);
+    }
+
+    @Test
+    public void testMigrateIkeSession_FromNotIkeTunnConnParams_AutoTimer() throws Exception {
+        doTestMigrateIkeSession_FromNotIkeTunnConnParams(
+                false /* isAutomaticIpVersionSelectionEnabled */,
+                true /* isAutomaticNattKeepaliveTimerEnabled */);
+    }
+
+    @Test
+    public void testMigrateIkeSession_FromNotIkeTunnConnParams_AutoIp() throws Exception {
+        doTestMigrateIkeSession_FromNotIkeTunnConnParams(
+                true /* isAutomaticIpVersionSelectionEnabled */,
+                false /* isAutomaticNattKeepaliveTimerEnabled */);
+    }
+
+    private void doTestMigrateIkeSession_FromNotIkeTunnConnParams(
+            boolean isAutomaticIpVersionSelectionEnabled,
+            boolean isAutomaticNattKeepaliveTimerEnabled) throws Exception {
+        final Ikev2VpnProfile ikeProfile =
+                new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY)
+                        .setAuthPsk(TEST_VPN_PSK)
+                        .setBypassable(true /* isBypassable */)
+                        .setAutomaticNattKeepaliveTimerEnabled(isAutomaticNattKeepaliveTimerEnabled)
+                        .setAutomaticIpVersionSelectionEnabled(isAutomaticIpVersionSelectionEnabled)
+                        .build();
+
+        final int expectedKeepalive = isAutomaticNattKeepaliveTimerEnabled
+                ? AUTOMATIC_KEEPALIVE_DELAY_SECONDS
+                : DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT;
+        doTestMigrateIkeSession(ikeProfile.toVpnProfile(),
+                expectedKeepalive,
+                ESP_IP_VERSION_AUTO /* expectedIpVersion */,
+                ESP_ENCAP_TYPE_AUTO /* expectedEncapType */,
+                new NetworkCapabilities.Builder().build());
+    }
+
+    private Ikev2VpnProfile makeIkeV2VpnProfile(
+            boolean isAutomaticIpVersionSelectionEnabled,
+            boolean isAutomaticNattKeepaliveTimerEnabled,
+            int keepaliveInProfile,
+            int ipVersionInProfile,
+            int encapTypeInProfile) {
+        // TODO: Update helper function in IkeSessionTestUtils to support building IkeSessionParams
+        // with IP version and encap type when mainline-prod branch support these two APIs.
+        final IkeSessionParams params = getTestIkeSessionParams(true /* testIpv6 */,
+                new IkeFqdnIdentification(TEST_IDENTITY), keepaliveInProfile);
+        final IkeSessionParams ikeSessionParams = new IkeSessionParams.Builder(params)
+                .setIpVersion(ipVersionInProfile)
+                .setEncapType(encapTypeInProfile)
+                .build();
+
+        final IkeTunnelConnectionParams tunnelParams =
+                new IkeTunnelConnectionParams(ikeSessionParams, CHILD_PARAMS);
+        return new Ikev2VpnProfile.Builder(tunnelParams)
+                .setBypassable(true)
+                .setAutomaticNattKeepaliveTimerEnabled(isAutomaticNattKeepaliveTimerEnabled)
+                .setAutomaticIpVersionSelectionEnabled(isAutomaticIpVersionSelectionEnabled)
+                .build();
+    }
+
+    private void doTestMigrateIkeSession_FromIkeTunnConnParams(
+            boolean isAutomaticIpVersionSelectionEnabled,
+            boolean isAutomaticNattKeepaliveTimerEnabled,
+            int keepaliveInProfile,
+            int ipVersionInProfile,
+            int encapTypeInProfile) throws Exception {
+        doTestMigrateIkeSession_FromIkeTunnConnParams(isAutomaticIpVersionSelectionEnabled,
+                isAutomaticNattKeepaliveTimerEnabled, keepaliveInProfile, ipVersionInProfile,
+                encapTypeInProfile, new NetworkCapabilities.Builder().build());
+    }
+
+    private void doTestMigrateIkeSession_FromIkeTunnConnParams(
+            boolean isAutomaticIpVersionSelectionEnabled,
+            boolean isAutomaticNattKeepaliveTimerEnabled,
+            int keepaliveInProfile,
+            int ipVersionInProfile,
+            int encapTypeInProfile,
+            @NonNull final NetworkCapabilities nc) throws Exception {
+        final Ikev2VpnProfile ikeProfile = makeIkeV2VpnProfile(
+                isAutomaticIpVersionSelectionEnabled,
+                isAutomaticNattKeepaliveTimerEnabled,
+                keepaliveInProfile,
+                ipVersionInProfile,
+                encapTypeInProfile);
+
+        final IkeSessionParams ikeSessionParams =
+                ikeProfile.getIkeTunnelConnectionParams().getIkeSessionParams();
+        final int expectedKeepalive = isAutomaticNattKeepaliveTimerEnabled
+                ? AUTOMATIC_KEEPALIVE_DELAY_SECONDS
+                : ikeSessionParams.getNattKeepAliveDelaySeconds();
+        final int expectedIpVersion = isAutomaticIpVersionSelectionEnabled
+                ? ESP_IP_VERSION_AUTO
+                : ikeSessionParams.getIpVersion();
+        final int expectedEncapType = isAutomaticIpVersionSelectionEnabled
+                ? ESP_ENCAP_TYPE_AUTO
+                : ikeSessionParams.getEncapType();
+        doTestMigrateIkeSession(ikeProfile.toVpnProfile(), expectedKeepalive,
+                expectedIpVersion, expectedEncapType, nc);
+    }
+
+    @Test
+    public void doTestMigrateIkeSession_Vcn() throws Exception {
+        final int expectedKeepalive = 2097; // Any unlikely number will do
+        final NetworkCapabilities vcnNc = new NetworkCapabilities.Builder()
+                .addTransportType(TRANSPORT_CELLULAR)
+                .setTransportInfo(new VcnTransportInfo(TEST_SUB_ID, expectedKeepalive))
+                .build();
+        final Ikev2VpnProfile ikev2VpnProfile = makeIkeV2VpnProfile(
+                true /* isAutomaticIpVersionSelectionEnabled */,
+                true /* isAutomaticNattKeepaliveTimerEnabled */,
+                234 /* keepaliveInProfile */, // Should be ignored, any value will do
+                ESP_IP_VERSION_IPV4, // Should be ignored
+                ESP_ENCAP_TYPE_UDP // Should be ignored
+        );
+        doTestMigrateIkeSession(
+                ikev2VpnProfile.toVpnProfile(),
+                expectedKeepalive,
+                ESP_IP_VERSION_AUTO /* expectedIpVersion */,
+                ESP_ENCAP_TYPE_AUTO /* expectedEncapType */,
+                vcnNc);
+    }
+
+    private void doTestMigrateIkeSession(
+            @NonNull final VpnProfile profile,
+            final int expectedKeepalive,
+            final int expectedIpVersion,
+            final int expectedEncapType,
+            @NonNull final NetworkCapabilities caps) throws Exception {
+        final PlatformVpnSnapshot vpnSnapShot =
+                verifySetupPlatformVpn(profile,
+                        createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */),
+                        caps /* underlying network capabilities */,
+                        false /* mtuSupportsIpv6 */,
+                        expectedKeepalive < DEFAULT_LONG_LIVED_TCP_CONNS_EXPENSIVE_TIMEOUT_SEC);
+        // Simulate a new network coming up
+        vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
+        verify(mIkeSessionWrapper, never()).setNetwork(any(), anyInt(), anyInt(), anyInt());
+
+        vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK_2, caps);
+        // Verify MOBIKE is triggered
+        verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).setNetwork(TEST_NETWORK_2,
+                expectedIpVersion, expectedEncapType, expectedKeepalive);
+
+        vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
+    }
+
+    @Test
+    public void testLinkPropertiesUpdateTriggerReevaluation() throws Exception {
+        final boolean hasV6 = true;
+
+        mockCarrierConfig(TEST_SUB_ID, TelephonyManager.SIM_STATE_LOADED, TEST_KEEPALIVE_TIMER,
+                PREFERRED_IKE_PROTOCOL_IPV6_ESP);
+        final IkeSessionParams params = getTestIkeSessionParams(hasV6,
+                new IkeFqdnIdentification(TEST_IDENTITY), TEST_KEEPALIVE_TIMER);
+        final IkeTunnelConnectionParams tunnelParams =
+                new IkeTunnelConnectionParams(params, CHILD_PARAMS);
+        final Ikev2VpnProfile ikeProfile = new Ikev2VpnProfile.Builder(tunnelParams)
+                .setBypassable(true)
+                .setAutomaticNattKeepaliveTimerEnabled(false)
+                .setAutomaticIpVersionSelectionEnabled(true)
+                .build();
+        final PlatformVpnSnapshot vpnSnapShot =
+                verifySetupPlatformVpn(ikeProfile.toVpnProfile(),
+                        createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */),
+                        new NetworkCapabilities.Builder().build() /* underlying network caps */,
+                        hasV6 /* mtuSupportsIpv6 */,
+                        false /* areLongLivedTcpConnectionsExpensive */);
+        reset(mExecutor);
+
+        // Simulate a new network coming up
+        final LinkProperties lp = new LinkProperties();
+        lp.addLinkAddress(new LinkAddress("192.0.2.2/32"));
+
+        // Have the executor use the real delay to make sure schedule() was called only
+        // once for all calls. Also, arrange for execute() not to call schedule() to avoid
+        // messing with the checks for schedule().
+        mExecutor.delayMs = TestExecutor.REAL_DELAY;
+        mExecutor.executeDirect = true;
+        vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
+        vpnSnapShot.nwCb.onCapabilitiesChanged(
+                TEST_NETWORK_2, new NetworkCapabilities.Builder().build());
+        vpnSnapShot.nwCb.onLinkPropertiesChanged(TEST_NETWORK_2, new LinkProperties(lp));
+        verify(mExecutor).schedule(any(Runnable.class), longThat(it -> it > 0), any());
+        reset(mExecutor);
+
+        final InOrder order = inOrder(mIkeSessionWrapper);
+
+        // Verify the network is started
+        order.verify(mIkeSessionWrapper, timeout(TIMEOUT_CROSSTHREAD_MS)).setNetwork(TEST_NETWORK_2,
+                ESP_IP_VERSION_AUTO, ESP_ENCAP_TYPE_AUTO, TEST_KEEPALIVE_TIMER);
+
+        // Send the same properties, check that no migration is scheduled
+        vpnSnapShot.nwCb.onLinkPropertiesChanged(TEST_NETWORK_2, new LinkProperties(lp));
+        verify(mExecutor, never()).schedule(any(Runnable.class), anyLong(), any());
+
+        // Add v6 address, verify MOBIKE is triggered
+        lp.addLinkAddress(new LinkAddress("2001:db8::1/64"));
+        vpnSnapShot.nwCb.onLinkPropertiesChanged(TEST_NETWORK_2, new LinkProperties(lp));
+        order.verify(mIkeSessionWrapper, timeout(TIMEOUT_CROSSTHREAD_MS)).setNetwork(TEST_NETWORK_2,
+                ESP_IP_VERSION_AUTO, ESP_ENCAP_TYPE_AUTO, TEST_KEEPALIVE_TIMER);
+
+        // Add another v4 address, verify MOBIKE is triggered
+        final LinkProperties stacked = new LinkProperties();
+        stacked.setInterfaceName("v4-" + lp.getInterfaceName());
+        stacked.addLinkAddress(new LinkAddress("192.168.0.1/32"));
+        lp.addStackedLink(stacked);
+        vpnSnapShot.nwCb.onLinkPropertiesChanged(TEST_NETWORK_2, new LinkProperties(lp));
+        order.verify(mIkeSessionWrapper, timeout(TIMEOUT_CROSSTHREAD_MS)).setNetwork(TEST_NETWORK_2,
+                ESP_IP_VERSION_AUTO, ESP_ENCAP_TYPE_AUTO, TEST_KEEPALIVE_TIMER);
+
+        vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
+    }
+
+    private void mockCarrierConfig(int subId, int simStatus, int keepaliveTimer, int ikeProtocol) {
+        final SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class);
+        doReturn(subId).when(subscriptionInfo).getSubscriptionId();
+        doReturn(List.of(subscriptionInfo)).when(mSubscriptionManager)
+                .getActiveSubscriptionInfoList();
+
+        doReturn(simStatus).when(mTmPerSub).getSimApplicationState();
+        doReturn(TEST_MCCMNC).when(mTmPerSub).getSimOperator(subId);
+
+        final PersistableBundle persistableBundle = new PersistableBundle();
+        persistableBundle.putInt(KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT, keepaliveTimer);
+        persistableBundle.putInt(KEY_PREFERRED_IKE_PROTOCOL_INT, ikeProtocol);
+        // For CarrierConfigManager.isConfigForIdentifiedCarrier check
+        persistableBundle.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
+        doReturn(persistableBundle).when(mConfigManager).getConfigForSubId(subId);
+    }
+
+    private CarrierConfigManager.CarrierConfigChangeListener getCarrierConfigListener() {
+        final ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerCaptor =
+                ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
+
+        verify(mConfigManager).registerCarrierConfigChangeListener(any(), listenerCaptor.capture());
+
+        return listenerCaptor.getValue();
+    }
+
+    @Test
+    public void testNattKeepaliveTimerFromCarrierConfig_noSubId() throws Exception {
+        doTestReadCarrierConfig(new NetworkCapabilities(),
+                TelephonyManager.SIM_STATE_LOADED,
+                PREFERRED_IKE_PROTOCOL_IPV4_UDP,
+                AUTOMATIC_KEEPALIVE_DELAY_SECONDS /* expectedKeepaliveTimer */,
+                ESP_IP_VERSION_AUTO /* expectedIpVersion */,
+                ESP_ENCAP_TYPE_AUTO /* expectedEncapType */,
+                false /* expectedReadFromCarrierConfig*/,
+                true /* areLongLivedTcpConnectionsExpensive */);
+    }
+
+    @Test
+    public void testNattKeepaliveTimerFromCarrierConfig_simAbsent() throws Exception {
+        doTestReadCarrierConfig(new NetworkCapabilities.Builder().build(),
+                TelephonyManager.SIM_STATE_ABSENT,
+                PREFERRED_IKE_PROTOCOL_IPV4_UDP,
+                AUTOMATIC_KEEPALIVE_DELAY_SECONDS /* expectedKeepaliveTimer */,
+                ESP_IP_VERSION_AUTO /* expectedIpVersion */,
+                ESP_ENCAP_TYPE_AUTO /* expectedEncapType */,
+                false /* expectedReadFromCarrierConfig*/,
+                true /* areLongLivedTcpConnectionsExpensive */);
+    }
+
+    @Test
+    public void testNattKeepaliveTimerFromCarrierConfig() throws Exception {
+        doTestReadCarrierConfig(createTestCellNc(),
+                TelephonyManager.SIM_STATE_LOADED,
+                PREFERRED_IKE_PROTOCOL_AUTO,
+                TEST_KEEPALIVE_TIMER /* expectedKeepaliveTimer */,
+                ESP_IP_VERSION_AUTO /* expectedIpVersion */,
+                ESP_ENCAP_TYPE_AUTO /* expectedEncapType */,
+                true /* expectedReadFromCarrierConfig*/,
+                false /* areLongLivedTcpConnectionsExpensive */);
+    }
+
+    @Test
+    public void testNattKeepaliveTimerFromCarrierConfig_NotCell() throws Exception {
+        final NetworkCapabilities nc = new NetworkCapabilities.Builder()
+                .addTransportType(TRANSPORT_WIFI)
+                .setTransportInfo(new WifiInfo.Builder().build())
+                .build();
+        doTestReadCarrierConfig(nc,
+                TelephonyManager.SIM_STATE_LOADED,
+                PREFERRED_IKE_PROTOCOL_IPV4_UDP,
+                AUTOMATIC_KEEPALIVE_DELAY_SECONDS /* expectedKeepaliveTimer */,
+                ESP_IP_VERSION_AUTO /* expectedIpVersion */,
+                ESP_ENCAP_TYPE_AUTO /* expectedEncapType */,
+                false /* expectedReadFromCarrierConfig*/,
+                true /* areLongLivedTcpConnectionsExpensive */);
+    }
+
+    @Test
+    public void testPreferredIpProtocolFromCarrierConfig_v4UDP() throws Exception {
+        doTestReadCarrierConfig(createTestCellNc(),
+                TelephonyManager.SIM_STATE_LOADED,
+                PREFERRED_IKE_PROTOCOL_IPV4_UDP,
+                TEST_KEEPALIVE_TIMER /* expectedKeepaliveTimer */,
+                ESP_IP_VERSION_IPV4 /* expectedIpVersion */,
+                ESP_ENCAP_TYPE_UDP /* expectedEncapType */,
+                true /* expectedReadFromCarrierConfig*/,
+                false /* areLongLivedTcpConnectionsExpensive */);
+    }
+
+    @Test
+    public void testPreferredIpProtocolFromCarrierConfig_v6ESP() throws Exception {
+        doTestReadCarrierConfig(createTestCellNc(),
+                TelephonyManager.SIM_STATE_LOADED,
+                PREFERRED_IKE_PROTOCOL_IPV6_ESP,
+                TEST_KEEPALIVE_TIMER /* expectedKeepaliveTimer */,
+                ESP_IP_VERSION_IPV6 /* expectedIpVersion */,
+                ESP_ENCAP_TYPE_NONE /* expectedEncapType */,
+                true /* expectedReadFromCarrierConfig*/,
+                false /* areLongLivedTcpConnectionsExpensive */);
+    }
+
+    @Test
+    public void testPreferredIpProtocolFromCarrierConfig_v6UDP() throws Exception {
+        doTestReadCarrierConfig(createTestCellNc(),
+                TelephonyManager.SIM_STATE_LOADED,
+                PREFERRED_IKE_PROTOCOL_IPV6_UDP,
+                TEST_KEEPALIVE_TIMER /* expectedKeepaliveTimer */,
+                ESP_IP_VERSION_IPV6 /* expectedIpVersion */,
+                ESP_ENCAP_TYPE_UDP /* expectedEncapType */,
+                true /* expectedReadFromCarrierConfig*/,
+                false /* areLongLivedTcpConnectionsExpensive */);
+    }
+
+    private NetworkCapabilities createTestCellNc() {
+        return new NetworkCapabilities.Builder()
+                .addTransportType(TRANSPORT_CELLULAR)
+                .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+                        .setSubscriptionId(TEST_SUB_ID)
+                        .build())
+                .build();
+    }
+
+    private void doTestReadCarrierConfig(NetworkCapabilities nc, int simState, int preferredIpProto,
+            int expectedKeepaliveTimer, int expectedIpVersion, int expectedEncapType,
+            boolean expectedReadFromCarrierConfig,
+            boolean areLongLivedTcpConnectionsExpensive)
+            throws Exception {
+        final Ikev2VpnProfile ikeProfile =
+                new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY)
+                        .setAuthPsk(TEST_VPN_PSK)
+                        .setBypassable(true /* isBypassable */)
+                        .setAutomaticNattKeepaliveTimerEnabled(true)
+                        .setAutomaticIpVersionSelectionEnabled(true)
+                        .build();
+
+        final PlatformVpnSnapshot vpnSnapShot =
+                verifySetupPlatformVpn(ikeProfile.toVpnProfile(),
+                        createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */),
+                        new NetworkCapabilities.Builder().build() /* underlying network caps */,
+                        false /* mtuSupportsIpv6 */,
+                        true /* areLongLivedTcpConnectionsExpensive */);
+
+        final CarrierConfigManager.CarrierConfigChangeListener listener =
+                getCarrierConfigListener();
+
+        // Simulate a new network coming up
+        vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
+        // Migration will not be started until receiving network capabilities change.
+        verify(mIkeSessionWrapper, never()).setNetwork(any(), anyInt(), anyInt(), anyInt());
+
+        reset(mIkeSessionWrapper);
+        mockCarrierConfig(TEST_SUB_ID, simState, TEST_KEEPALIVE_TIMER, preferredIpProto);
+        vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK_2, nc);
+        verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).setNetwork(TEST_NETWORK_2,
+                expectedIpVersion, expectedEncapType, expectedKeepaliveTimer);
+        if (expectedReadFromCarrierConfig) {
+            final ArgumentCaptor<NetworkCapabilities> ncCaptor =
+                    ArgumentCaptor.forClass(NetworkCapabilities.class);
+            verify(mMockNetworkAgent, timeout(TEST_TIMEOUT_MS))
+                    .doSendNetworkCapabilities(ncCaptor.capture());
+
+            final VpnTransportInfo info =
+                    (VpnTransportInfo) ncCaptor.getValue().getTransportInfo();
+            assertEquals(areLongLivedTcpConnectionsExpensive,
+                    info.areLongLivedTcpConnectionsExpensive());
+        } else {
+            verify(mMockNetworkAgent, never()).doSendNetworkCapabilities(any());
+        }
+
+        reset(mExecutor);
+        reset(mIkeSessionWrapper);
+        reset(mMockNetworkAgent);
+
+        // Trigger carrier config change
+        listener.onCarrierConfigChanged(1 /* logicalSlotIndex */, TEST_SUB_ID,
+                -1 /* carrierId */, -1 /* specificCarrierId */);
+        verify(mIkeSessionWrapper).setNetwork(TEST_NETWORK_2,
+                expectedIpVersion, expectedEncapType, expectedKeepaliveTimer);
+        // Expect no NetworkCapabilities change.
+        // Call to doSendNetworkCapabilities() will not be triggered.
+        verify(mMockNetworkAgent, never()).doSendNetworkCapabilities(any());
+    }
+
+    @Test
+    public void testStartPlatformVpn_mtuDoesNotSupportIpv6() throws Exception {
+        final PlatformVpnSnapshot vpnSnapShot =
+                verifySetupPlatformVpn(
+                        createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */),
+                        false /* mtuSupportsIpv6 */);
+        vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
+    }
+
+    @Test
+    public void testStartPlatformVpn_underlyingNetworkNotChange() throws Exception {
+        final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
+                createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
+        // Trigger update on the same network should not cause underlying network change in NC of
+        // the VPN network
+        vpnSnapShot.nwCb.onAvailable(TEST_NETWORK);
+        vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK,
+                new NetworkCapabilities.Builder()
+                        .setSubscriptionIds(Set.of(TEST_SUB_ID))
+                        .build());
+        // Verify setNetwork() called but no underlying network update
+        verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).setNetwork(eq(TEST_NETWORK),
+                eq(ESP_IP_VERSION_AUTO) /* ipVersion */,
+                eq(ESP_ENCAP_TYPE_AUTO) /* encapType */,
+                eq(DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT) /* keepaliveDelay */);
+        verify(mMockNetworkAgent, never())
+                .doSetUnderlyingNetworks(any());
+
+        vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
+        vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK_2,
+                new NetworkCapabilities.Builder().build());
+
+        // A new network should trigger both setNetwork() and a underlying network update.
+        verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).setNetwork(eq(TEST_NETWORK_2),
+                eq(ESP_IP_VERSION_AUTO) /* ipVersion */,
+                eq(ESP_ENCAP_TYPE_AUTO) /* encapType */,
+                eq(DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT) /* keepaliveDelay */);
+        verify(mMockNetworkAgent).doSetUnderlyingNetworks(
+                Collections.singletonList(TEST_NETWORK_2));
+
+        vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
+    }
+
+    @Test
+    public void testStartPlatformVpnMobility_mobikeEnabled() throws Exception {
+        final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
+                createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
+
+        // Set new MTU on a different network
+        final int newMtu = IPV6_MIN_MTU + 1;
+        doReturn(newMtu).when(mTestDeps).calculateVpnMtu(any(), anyInt(), anyInt(), anyBoolean());
+
+        // Mock network loss and verify a cleanup task is scheduled
+        vpnSnapShot.nwCb.onLost(TEST_NETWORK);
+        verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any());
+
+        // Mock new network comes up and the cleanup task is cancelled
+        vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
+        verify(mIkeSessionWrapper, never()).setNetwork(any(), anyInt(), anyInt(), anyInt());
+
+        vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK_2,
+                new NetworkCapabilities.Builder().build());
+        // Verify MOBIKE is triggered
+        verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).setNetwork(eq(TEST_NETWORK_2),
+                eq(ESP_IP_VERSION_AUTO) /* ipVersion */,
+                eq(ESP_ENCAP_TYPE_AUTO) /* encapType */,
+                eq(DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT) /* keepaliveDelay */);
+        // Verify mNetworkCapabilities is updated
+        assertEquals(
+                Collections.singletonList(TEST_NETWORK_2),
+                vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks());
+        verify(mMockNetworkAgent)
+                .doSetUnderlyingNetworks(Collections.singletonList(TEST_NETWORK_2));
+
+        // Mock the MOBIKE procedure
+        vpnSnapShot.ikeCb.onIkeSessionConnectionInfoChanged(createIkeConnectInfo_2());
+        vpnSnapShot.childCb.onIpSecTransformsMigrated(
+                createIpSecTransform(), createIpSecTransform());
+
+        verify(mIpSecService).setNetworkForTunnelInterface(
+                eq(TEST_TUNNEL_RESOURCE_ID), eq(TEST_NETWORK_2), anyString());
+
+        // Expect 2 times: one for initial setup and one for MOBIKE
+        verifyApplyTunnelModeTransforms(2);
+
+        // Verify mNetworkAgent is updated
+        verify(mMockNetworkAgent).doSendLinkProperties(argThat(lp -> lp.getMtu() == newMtu));
+        verify(mMockNetworkAgent, never()).unregister();
+        // No further doSetUnderlyingNetworks interaction. The interaction count should stay one.
+        verify(mMockNetworkAgent, times(1)).doSetUnderlyingNetworks(any());
+        vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
+    }
+
+    @Test
+    public void testStartPlatformVpnMobility_mobikeEnabledMtuDoesNotSupportIpv6() throws Exception {
+        final PlatformVpnSnapshot vpnSnapShot =
+                verifySetupPlatformVpn(
+                        createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
+
+        // Set MTU below 1280
+        final int newMtu = IPV6_MIN_MTU - 1;
+        doReturn(newMtu).when(mTestDeps).calculateVpnMtu(any(), anyInt(), anyInt(), anyBoolean());
+
+        // Mock new network available & MOBIKE procedures
+        vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
+        vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK_2,
+                new NetworkCapabilities.Builder().build());
+        // Verify mNetworkCapabilities is updated
+        verify(mMockNetworkAgent, timeout(TEST_TIMEOUT_MS))
+                .doSetUnderlyingNetworks(Collections.singletonList(TEST_NETWORK_2));
+        assertEquals(
+                Collections.singletonList(TEST_NETWORK_2),
+                vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks());
+
+        vpnSnapShot.ikeCb.onIkeSessionConnectionInfoChanged(createIkeConnectInfo_2());
+        vpnSnapShot.childCb.onIpSecTransformsMigrated(
+                createIpSecTransform(), createIpSecTransform());
+
+        // Verify removal of IPv6 addresses and routes triggers a network agent restart
+        final ArgumentCaptor<LinkProperties> lpCaptor =
+                ArgumentCaptor.forClass(LinkProperties.class);
+        verify(mTestDeps, times(2))
+                .newNetworkAgent(any(), any(), anyString(), any(), lpCaptor.capture(), any(), any(),
+                        any(), any());
+        verify(mMockNetworkAgent).unregister();
+        // mMockNetworkAgent is an old NetworkAgent, so it won't update LinkProperties after
+        // unregistering.
+        verify(mMockNetworkAgent, never()).doSendLinkProperties(any());
+
+        final LinkProperties lp = lpCaptor.getValue();
+
+        for (LinkAddress addr : lp.getLinkAddresses()) {
+            if (addr.isIpv6()) {
+                fail("IPv6 address found on VPN with MTU < IPv6 minimum MTU");
+            }
+        }
+
+        for (InetAddress dnsAddr : lp.getDnsServers()) {
+            if (dnsAddr instanceof Inet6Address) {
+                fail("IPv6 DNS server found on VPN with MTU < IPv6 minimum MTU");
+            }
+        }
+
+        for (RouteInfo routeInfo : lp.getRoutes()) {
+            if (routeInfo.getDestinationLinkAddress().isIpv6()
+                    && !routeInfo.isIPv6UnreachableDefault()) {
+                fail("IPv6 route found on VPN with MTU < IPv6 minimum MTU");
+            }
+        }
+
+        assertEquals(newMtu, lp.getMtu());
+
+        vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
+    }
+
+    @Test
+    public void testStartPlatformVpnReestablishes_mobikeDisabled() throws Exception {
+        final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
+                createIkeConfig(createIkeConnectInfo(), false /* isMobikeEnabled */));
+
+        // Forget the first IKE creation to be prepared to capture callbacks of the second
+        // IKE session
+        resetIkev2SessionCreator(mock(Vpn.IkeSessionWrapper.class));
+
+        // Mock network switch
+        vpnSnapShot.nwCb.onLost(TEST_NETWORK);
+        vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
+        // The old IKE Session will not be killed until receiving network capabilities change.
+        verify(mIkeSessionWrapper, never()).kill();
+
+        vpnSnapShot.nwCb.onCapabilitiesChanged(
+                TEST_NETWORK_2, new NetworkCapabilities.Builder().build());
+        // Verify the old IKE Session is killed
+        verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).kill();
+
+        // Capture callbacks of the new IKE Session
+        final Pair<IkeSessionCallback, ChildSessionCallback> cbPair =
+                verifyCreateIkeAndCaptureCbs();
+        final IkeSessionCallback ikeCb = cbPair.first;
+        final ChildSessionCallback childCb = cbPair.second;
+
+        // Mock the IKE Session setup
+        ikeCb.onOpened(createIkeConfig(createIkeConnectInfo_2(), false /* isMobikeEnabled */));
+
+        childCb.onIpSecTransformCreated(createIpSecTransform(), IpSecManager.DIRECTION_IN);
+        childCb.onIpSecTransformCreated(createIpSecTransform(), IpSecManager.DIRECTION_OUT);
+        childCb.onOpened(createChildConfig());
+
+        // Expect 2 times since there have been two Session setups
+        verifyApplyTunnelModeTransforms(2);
+
+        // Verify mNetworkCapabilities and mNetworkAgent are updated
+        assertEquals(
+                Collections.singletonList(TEST_NETWORK_2),
+                vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks());
+        verify(mMockNetworkAgent)
+                .doSetUnderlyingNetworks(Collections.singletonList(TEST_NETWORK_2));
+
+        vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
+    }
+
+    private String getDump(@NonNull final Vpn vpn) {
+        final StringWriter sw = new StringWriter();
+        final IndentingPrintWriter writer = new IndentingPrintWriter(sw, "");
+        vpn.dump(writer);
+        writer.flush();
+        return sw.toString();
+    }
+
+    private int countMatches(@NonNull final Pattern regexp, @NonNull final String string) {
+        final Matcher m = regexp.matcher(string);
+        int i = 0;
+        while (m.find()) ++i;
+        return i;
+    }
+
+    @Test
+    public void testNCEventChanges() throws Exception {
+        final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder()
+                .addTransportType(TRANSPORT_CELLULAR)
+                .addCapability(NET_CAPABILITY_INTERNET)
+                .addCapability(NET_CAPABILITY_NOT_RESTRICTED)
+                .setLinkDownstreamBandwidthKbps(1000)
+                .setLinkUpstreamBandwidthKbps(500);
+
+        final Ikev2VpnProfile ikeProfile =
+                new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY)
+                        .setAuthPsk(TEST_VPN_PSK)
+                        .setBypassable(true /* isBypassable */)
+                        .setAutomaticNattKeepaliveTimerEnabled(true)
+                        .setAutomaticIpVersionSelectionEnabled(true)
+                        .build();
+
+        final PlatformVpnSnapshot vpnSnapShot =
+                verifySetupPlatformVpn(ikeProfile.toVpnProfile(),
+                        createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */),
+                        ncBuilder.build(), false /* mtuSupportsIpv6 */,
+                        true /* areLongLivedTcpConnectionsExpensive */);
+
+        // Calls to onCapabilitiesChanged will be thrown to the executor for execution ; by
+        // default this will incur a 10ms delay before it's executed, messing with the timing
+        // of the log and having the checks for counts in equals() below flake.
+        mExecutor.executeDirect = true;
+
+        // First nc changed triggered by verifySetupPlatformVpn
+        final Pattern pattern = Pattern.compile("Cap changed from", Pattern.MULTILINE);
+        final String stage1 = getDump(vpnSnapShot.vpn);
+        assertEquals(1, countMatches(pattern, stage1));
+
+        vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK, ncBuilder.build());
+        final String stage2 = getDump(vpnSnapShot.vpn);
+        // Was the same caps, there should still be only 1 match
+        assertEquals(1, countMatches(pattern, stage2));
+
+        ncBuilder.setLinkDownstreamBandwidthKbps(1200)
+                .setLinkUpstreamBandwidthKbps(300);
+        vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK, ncBuilder.build());
+        final String stage3 = getDump(vpnSnapShot.vpn);
+        // Was not an important change, should not be logged, still only 1 match
+        assertEquals(1, countMatches(pattern, stage3));
+
+        ncBuilder.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+        vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK, ncBuilder.build());
+        final String stage4 = getDump(vpnSnapShot.vpn);
+        // Change to caps is important, should cause a new match
+        assertEquals(2, countMatches(pattern, stage4));
+
+        ncBuilder.removeCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+        ncBuilder.setLinkDownstreamBandwidthKbps(600);
+        vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK, ncBuilder.build());
+        final String stage5 = getDump(vpnSnapShot.vpn);
+        // Change to caps is important, should cause a new match even with the unimportant change
+        assertEquals(3, countMatches(pattern, stage5));
+    }
+    // TODO : beef up event logs tests
+
+    private void verifyHandlingNetworkLoss(PlatformVpnSnapshot vpnSnapShot) throws Exception {
+        // Forget the #sendLinkProperties during first setup.
+        reset(mMockNetworkAgent);
+
+        // Mock network loss
+        vpnSnapShot.nwCb.onLost(TEST_NETWORK);
+
+        // Mock the grace period expires
+        verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any());
+
+        final ArgumentCaptor<LinkProperties> lpCaptor =
+                ArgumentCaptor.forClass(LinkProperties.class);
+        verify(mMockNetworkAgent, timeout(TEST_TIMEOUT_MS))
+                .doSendLinkProperties(lpCaptor.capture());
+        final LinkProperties lp = lpCaptor.getValue();
+
+        assertNull(lp.getInterfaceName());
+        final List<RouteInfo> expectedRoutes = Arrays.asList(
+                new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null /* gateway */,
+                        null /* iface */, RTN_UNREACHABLE),
+                new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /* gateway */,
+                        null /* iface */, RTN_UNREACHABLE));
+        assertEquals(expectedRoutes, lp.getRoutes());
+
+        verify(mMockNetworkAgent, timeout(TEST_TIMEOUT_MS)).unregister();
+    }
+
+    @Test
+    public void testStartPlatformVpnHandlesNetworkLoss_mobikeEnabled() throws Exception {
+        final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
+                createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
+        verifyHandlingNetworkLoss(vpnSnapShot);
+    }
+
+    @Test
+    public void testStartPlatformVpnHandlesNetworkLoss_mobikeDisabled() throws Exception {
+        final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
+                createIkeConfig(createIkeConnectInfo(), false /* isMobikeEnabled */));
+        verifyHandlingNetworkLoss(vpnSnapShot);
+    }
+
+    private ConnectivityDiagnosticsCallback getConnectivityDiagCallback() {
+        final ArgumentCaptor<ConnectivityDiagnosticsCallback> cdcCaptor =
+                ArgumentCaptor.forClass(ConnectivityDiagnosticsCallback.class);
+        verify(mCdm).registerConnectivityDiagnosticsCallback(
+                any(), any(), cdcCaptor.capture());
+        return cdcCaptor.getValue();
+    }
+
+    private DataStallReport createDataStallReport() {
+        return new DataStallReport(TEST_NETWORK, 1234 /* reportTimestamp */,
+                1 /* detectionMethod */, new LinkProperties(), new NetworkCapabilities(),
+                new PersistableBundle());
+    }
+
+    private void verifyMobikeTriggered(List<Network> expected, int retryIndex) {
+        // Verify retry is scheduled
+        final long expectedDelayMs = mTestDeps.getValidationFailRecoveryMs(retryIndex);
+        final ArgumentCaptor<Long> delayCaptor = ArgumentCaptor.forClass(Long.class);
+        verify(mExecutor, times(retryIndex + 1)).schedule(
+                any(Runnable.class), delayCaptor.capture(), eq(TimeUnit.MILLISECONDS));
+        final List<Long> delays = delayCaptor.getAllValues();
+        assertEquals(expectedDelayMs, (long) delays.get(delays.size() - 1));
+
+        final ArgumentCaptor<Network> networkCaptor = ArgumentCaptor.forClass(Network.class);
+        verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS + expectedDelayMs))
+                .setNetwork(networkCaptor.capture(), anyInt() /* ipVersion */,
+                        anyInt() /* encapType */, anyInt() /* keepaliveDelay */);
+        assertEquals(expected, Collections.singletonList(networkCaptor.getValue()));
+    }
+
+    @Test
+    public void testDataStallInIkev2VpnMobikeDisabled() throws Exception {
+        final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
+                createIkeConfig(createIkeConnectInfo(), false /* isMobikeEnabled */));
+
+        doReturn(TEST_NETWORK).when(mMockNetworkAgent).getNetwork();
+        ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
+                NetworkAgent.VALIDATION_STATUS_NOT_VALID);
+
+        // Should not trigger MOBIKE if MOBIKE is not enabled
+        verify(mIkeSessionWrapper, never()).setNetwork(any() /* network */,
+                anyInt() /* ipVersion */, anyInt() /* encapType */, anyInt() /* keepaliveDelay */);
+    }
+
+    @Test
+    public void testDataStallInIkev2VpnRecoveredByMobike() throws Exception {
+        final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
+                createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
+
+        doReturn(TEST_NETWORK).when(mMockNetworkAgent).getNetwork();
+        ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
+                NetworkAgent.VALIDATION_STATUS_NOT_VALID);
+        // Verify MOBIKE is triggered
+        verifyMobikeTriggered(vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks(),
+                0 /* retryIndex */);
+        // Validation failure on VPN network should trigger a re-evaluation request for the
+        // underlying network.
+        verify(mConnectivityManager).reportNetworkConnectivity(TEST_NETWORK, false);
+
+        reset(mIkev2SessionCreator);
+        reset(mExecutor);
+
+        // Send validation status update.
+        // Recovered and get network validated. It should not trigger the ike session reset.
+        ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
+                NetworkAgent.VALIDATION_STATUS_VALID);
+        // Verify that the retry count is reset. The mValidationFailRetryCount will not be reset
+        // until the executor finishes the execute() call, so wait until the all tasks are executed.
+        waitForIdleSerialExecutor(mExecutor, TEST_TIMEOUT_MS);
+        assertEquals(0,
+                ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).mValidationFailRetryCount);
+        verify(mIkev2SessionCreator, never()).createIkeSession(
+                any(), any(), any(), any(), any(), any());
+
+        reset(mIkeSessionWrapper);
+        reset(mExecutor);
+
+        // Another validation fail should trigger another reportNetworkConnectivity
+        ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
+                NetworkAgent.VALIDATION_STATUS_NOT_VALID);
+        verifyMobikeTriggered(vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks(),
+                0 /* retryIndex */);
+        verify(mConnectivityManager, times(2)).reportNetworkConnectivity(TEST_NETWORK, false);
+    }
+
+    @Test
+    public void testDataStallInIkev2VpnNotRecoveredByMobike() throws Exception {
+        final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
+                createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
+
+        int retry = 0;
+        doReturn(TEST_NETWORK).when(mMockNetworkAgent).getNetwork();
+        ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
+                NetworkAgent.VALIDATION_STATUS_NOT_VALID);
+        verifyMobikeTriggered(vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks(),
+                retry++);
+        // Validation failure on VPN network should trigger a re-evaluation request for the
+        // underlying network.
+        verify(mConnectivityManager).reportNetworkConnectivity(TEST_NETWORK, false);
+        reset(mIkev2SessionCreator);
+
+        // Second validation status update.
+        ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
+                NetworkAgent.VALIDATION_STATUS_NOT_VALID);
+        verifyMobikeTriggered(vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks(),
+                retry++);
+        // Call to reportNetworkConnectivity should only happen once. No further interaction.
+        verify(mConnectivityManager, times(1)).reportNetworkConnectivity(TEST_NETWORK, false);
+
+        // Use real delay to verify reset session will not be performed if there is an existing
+        // recovery for resetting the session.
+        mExecutor.delayMs = TestExecutor.REAL_DELAY;
+        mExecutor.executeDirect = true;
+        // Send validation status update should result in ike session reset.
+        ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
+                NetworkAgent.VALIDATION_STATUS_NOT_VALID);
+
+        // Verify session reset is scheduled
+        long expectedDelay = mTestDeps.getValidationFailRecoveryMs(retry++);
+        final ArgumentCaptor<Long> delayCaptor = ArgumentCaptor.forClass(Long.class);
+        verify(mExecutor, times(retry)).schedule(any(Runnable.class), delayCaptor.capture(),
+                eq(TimeUnit.MILLISECONDS));
+        final List<Long> delays = delayCaptor.getAllValues();
+        assertEquals(expectedDelay, (long) delays.get(delays.size() - 1));
+        // Call to reportNetworkConnectivity should only happen once. No further interaction.
+        verify(mConnectivityManager, times(1)).reportNetworkConnectivity(TEST_NETWORK, false);
+
+        // Another invalid status reported should not trigger other scheduled recovery.
+        expectedDelay = mTestDeps.getValidationFailRecoveryMs(retry++);
+        ((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
+                NetworkAgent.VALIDATION_STATUS_NOT_VALID);
+        verify(mExecutor, never()).schedule(
+                any(Runnable.class), eq(expectedDelay), eq(TimeUnit.MILLISECONDS));
+
+        // Verify that session being reset
+        verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS + expectedDelay))
+                .createIkeSession(any(), any(), any(), any(), any(), any());
+        // Call to reportNetworkConnectivity should only happen once. No further interaction.
+        verify(mConnectivityManager, times(1)).reportNetworkConnectivity(TEST_NETWORK, false);
+    }
+
+    @Test
+    public void testStartLegacyVpnType() throws Exception {
+        setMockedUsers(PRIMARY_USER);
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+        final VpnProfile profile = new VpnProfile("testProfile" /* key */);
+
+        profile.type = VpnProfile.TYPE_PPTP;
+        assertThrows(UnsupportedOperationException.class, () -> startLegacyVpn(vpn, profile));
+        profile.type = VpnProfile.TYPE_L2TP_IPSEC_PSK;
+        assertThrows(UnsupportedOperationException.class, () -> startLegacyVpn(vpn, profile));
+    }
+
+    @Test
+    public void testStartLegacyVpnModifyProfile_TypePSK() throws Exception {
+        setMockedUsers(PRIMARY_USER);
+        final Vpn vpn = createVpn(PRIMARY_USER.id);
+        final Ikev2VpnProfile ikev2VpnProfile =
+                new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY)
+                        .setAuthPsk(TEST_VPN_PSK)
+                        .build();
+        final VpnProfile profile = ikev2VpnProfile.toVpnProfile();
+
+        startLegacyVpn(vpn, profile);
+        assertEquals(profile, ikev2VpnProfile.toVpnProfile());
+    }
+
+    private void assertTransportInfoMatches(NetworkCapabilities nc, int type) {
+        assertNotNull(nc);
+        VpnTransportInfo ti = (VpnTransportInfo) nc.getTransportInfo();
+        assertNotNull(ti);
+        assertEquals(type, ti.getType());
+    }
+
+    // Make it public and un-final so as to spy it
+    public class TestDeps extends Vpn.Dependencies {
+        TestDeps() {}
+
+        @Override
+        public boolean isCallerSystem() {
+            return true;
+        }
+
+        @Override
+        public PendingIntent getIntentForStatusPanel(Context context) {
+            return null;
+        }
+
+        @Override
+        public ParcelFileDescriptor adoptFd(Vpn vpn, int mtu) {
+            return new ParcelFileDescriptor(new FileDescriptor());
+        }
+
+        @Override
+        public int jniCreate(Vpn vpn, int mtu) {
+            // Pick a random positive number as fd to return.
+            return 345;
+        }
+
+        @Override
+        public String jniGetName(Vpn vpn, int fd) {
+            return TEST_IFACE_NAME;
+        }
+
+        @Override
+        public int jniSetAddresses(Vpn vpn, String interfaze, String addresses) {
+            if (addresses == null) return 0;
+            // Return the number of addresses.
+            return addresses.split(" ").length;
+        }
+
+        @Override
+        public void setBlocking(FileDescriptor fd, boolean blocking) {}
+
+        @Override
+        public DeviceIdleInternal getDeviceIdleInternal() {
+            return mDeviceIdleInternal;
+        }
+
+        @Override
+        public long getValidationFailRecoveryMs(int retryCount) {
+            // Simply return retryCount as the delay seconds for retrying.
+            return retryCount * 100L;
+        }
+
+        @Override
+        public ScheduledThreadPoolExecutor newScheduledThreadPoolExecutor() {
+            return mExecutor;
+        }
+
+        public boolean mIgnoreCallingUidChecks = true;
+        @Override
+        public void verifyCallingUidAndPackage(Context context, String packageName, int userId) {
+            if (!mIgnoreCallingUidChecks) {
+                super.verifyCallingUidAndPackage(context, packageName, userId);
+            }
+        }
+    }
+
+    /**
+     * Mock some methods of vpn object.
+     */
+    private Vpn createVpn(@UserIdInt int userId) {
+        final Context asUserContext = mock(Context.class, AdditionalAnswers.delegatesTo(mContext));
+        doReturn(UserHandle.of(userId)).when(asUserContext).getUser();
+        when(mContext.createContextAsUser(eq(UserHandle.of(userId)), anyInt()))
+                .thenReturn(asUserContext);
+        final TestLooper testLooper = new TestLooper();
+        final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, mTestDeps, mNetService,
+                mNetd, userId, mVpnProfileStore, mSystemServices, mIkev2SessionCreator);
+        verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat(
+                provider -> provider.getName().contains("VpnNetworkProvider")
+        ));
+        return vpn;
+    }
+
+    /**
+     * Populate {@link #mUserManager} with a list of fake users.
+     */
+    private void setMockedUsers(UserInfo... users) {
+        final Map<Integer, UserInfo> userMap = new ArrayMap<>();
+        for (UserInfo user : users) {
+            userMap.put(user.id, user);
+        }
+
+        /**
+         * @see UserManagerService#getUsers(boolean)
+         */
+        doAnswer(invocation -> {
+            final ArrayList<UserInfo> result = new ArrayList<>(users.length);
+            for (UserInfo ui : users) {
+                if (ui.isEnabled() && !ui.partial) {
+                    result.add(ui);
+                }
+            }
+            return result;
+        }).when(mUserManager).getAliveUsers();
+
+        doAnswer(invocation -> {
+            final int id = (int) invocation.getArguments()[0];
+            return userMap.get(id);
+        }).when(mUserManager).getUserInfo(anyInt());
+    }
+
+    /**
+     * Populate {@link #mPackageManager} with a fake packageName-to-UID mapping.
+     */
+    private void setMockedPackages(final Map<String, Integer> packages) {
+        try {
+            doAnswer(invocation -> {
+                final String appName = (String) invocation.getArguments()[0];
+                final int userId = (int) invocation.getArguments()[1];
+                Integer appId = packages.get(appName);
+                if (appId == null) throw new PackageManager.NameNotFoundException(appName);
+                return UserHandle.getUid(userId, appId);
+            }).when(mPackageManager).getPackageUidAsUser(anyString(), anyInt());
+        } catch (Exception e) {
+        }
+    }
+}
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 418b78c..9c9aeea 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.display;
 
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED;
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE;
@@ -1016,4 +1017,34 @@
         listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500));
         assertEquals(500, mController.getAmbientLux(), EPSILON);
     }
+
+    @Test
+    public void testBrightnessBasedOnLastObservedLux() throws Exception {
+        ArgumentCaptor<SensorEventListener> listenerCaptor =
+                ArgumentCaptor.forClass(SensorEventListener.class);
+        verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
+                eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+        SensorEventListener listener = listenerCaptor.getValue();
+
+        // Set up system to return 0.3f as a brightness value
+        float lux = 100.0f;
+        // Brightness as float (from 0.0f to 1.0f)
+        float normalizedBrightness = 0.3f;
+        when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux)).thenReturn(lux);
+        when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux)).thenReturn(lux);
+        when(mBrightnessMappingStrategy.getBrightness(eq(lux), eq(null), anyInt()))
+                .thenReturn(normalizedBrightness);
+        when(mBrightnessThrottler.getBrightnessCap()).thenReturn(BRIGHTNESS_MAX_FLOAT);
+        when(mBrightnessThrottler.isThrottled()).thenReturn(true);
+
+        // Send a new sensor value, disable the sensor and verify
+        listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux));
+        mController.configure(AUTO_BRIGHTNESS_DISABLED, /* configuration= */ null,
+                /* brightness= */ 0, /* userChangedBrightness= */ false, /* adjustment= */ 0,
+                /* userChanged= */ false, DisplayPowerRequest.POLICY_BRIGHT,
+                /* shouldResetShortTermModel= */ true);
+        assertEquals(normalizedBrightness,
+                mController.getAutomaticScreenBrightnessBasedOnLastObservedLux(
+                        /* brightnessEvent= */ null), EPSILON);
+    }
 }
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 807774f..e9315c8 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1665,6 +1665,89 @@
                 /* luxTimestamps= */ any());
     }
 
+    @Test
+    public void testInitialDozeBrightness() {
+        when(mDisplayManagerFlagsMock.areAutoBrightnessModesEnabled()).thenReturn(true);
+        when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
+        mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.SCREEN_BRIGHTNESS_MODE,
+                Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, false);
+        float brightness = 0.277f;
+        when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+        when(mHolder.automaticBrightnessController
+                .getAutomaticScreenBrightnessBasedOnLastObservedLux(any(BrightnessEvent.class)))
+                .thenReturn(brightness);
+        when(mHolder.hbmController.getCurrentBrightnessMax())
+                .thenReturn(PowerManager.BRIGHTNESS_MAX);
+        when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE);
+
+        DisplayPowerRequest dpr = new DisplayPowerRequest();
+        dpr.policy = DisplayPowerRequest.POLICY_DOZE;
+        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+        advanceTime(1); // Run updatePowerState
+
+        verify(mHolder.animator).animateTo(eq(brightness),
+                /* linearSecondTarget= */ anyFloat(), /* rate= */ anyFloat(),
+                /* ignoreAnimationLimits= */ anyBoolean());
+    }
+
+    @Test
+    public void testInitialDozeBrightness_AbcIsNull() {
+        when(mDisplayManagerFlagsMock.areAutoBrightnessModesEnabled()).thenReturn(true);
+        when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.SCREEN_BRIGHTNESS_MODE,
+                Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, false);
+        mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ true,
+                /* isAutoBrightnessAvailable= */ false);
+        mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
+        float brightness = 0.277f;
+        when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+        when(mHolder.automaticBrightnessController
+                .getAutomaticScreenBrightnessBasedOnLastObservedLux(any(BrightnessEvent.class)))
+                .thenReturn(brightness);
+        when(mHolder.hbmController.getCurrentBrightnessMax())
+                .thenReturn(PowerManager.BRIGHTNESS_MAX);
+        when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE);
+
+        DisplayPowerRequest dpr = new DisplayPowerRequest();
+        dpr.policy = DisplayPowerRequest.POLICY_DOZE;
+        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+        advanceTime(1); // Run updatePowerState
+
+        // Automatic Brightness Controller is null so no initial doze brightness should be set and
+        // we should not crash
+        verify(mHolder.animator, never()).animateTo(eq(brightness),
+                /* linearSecondTarget= */ anyFloat(), /* rate= */ anyFloat(),
+                /* ignoreAnimationLimits= */ anyBoolean());
+    }
+
+    @Test
+    public void testDefaultDozeBrightness() {
+        float brightness = 0.121f;
+        when(mPowerManagerMock.getBrightnessConstraint(
+                PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DOZE)).thenReturn(brightness);
+        mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
+        when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+        when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+                any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+        when(mHolder.hbmController.getCurrentBrightnessMax())
+                .thenReturn(PowerManager.BRIGHTNESS_MAX);
+
+        DisplayPowerRequest dpr = new DisplayPowerRequest();
+        dpr.policy = DisplayPowerRequest.POLICY_DOZE;
+        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+        advanceTime(1); // Run updatePowerState
+
+        verify(mHolder.animator).animateTo(eq(brightness), /* linearSecondTarget= */ anyFloat(),
+                eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false));
+    }
+
     /**
      * Creates a mock and registers it to {@link LocalServices}.
      */
@@ -1749,6 +1832,12 @@
 
     private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
             String uniqueId, boolean isEnabled) {
+        return createDisplayPowerController(displayId, uniqueId, isEnabled,
+                /* isAutoBrightnessAvailable= */ true);
+    }
+
+    private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
+            String uniqueId, boolean isEnabled, boolean isAutoBrightnessAvailable) {
         final DisplayPowerState displayPowerState = mock(DisplayPowerState.class);
         final DualRampAnimator<DisplayPowerState> animator = mock(DualRampAnimator.class);
         final AutomaticBrightnessController automaticBrightnessController =
@@ -1783,6 +1872,7 @@
         final DisplayDeviceConfig config = mock(DisplayDeviceConfig.class);
 
         setUpDisplay(displayId, uniqueId, display, device, config, isEnabled);
+        when(config.isAutoBrightnessAvailable()).thenReturn(isAutoBrightnessAvailable);
 
         final DisplayPowerController dpc = new DisplayPowerController(
                 mContext, injector, mDisplayPowerCallbacksMock, mHandler,
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java
index c0c63c6..397d77c 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java
@@ -16,9 +16,14 @@
 
 package com.android.server.display.brightness;
 
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE;
+
 import static org.junit.Assert.assertEquals;
 
 import android.hardware.display.BrightnessInfo;
+import android.view.Display;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -39,6 +44,8 @@
         mBrightnessEvent.setReason(
                 getReason(BrightnessReason.REASON_DOZE, BrightnessReason.MODIFIER_LOW_POWER));
         mBrightnessEvent.setPhysicalDisplayId("test");
+        mBrightnessEvent.setDisplayState(Display.STATE_ON);
+        mBrightnessEvent.setDisplayPolicy(POLICY_BRIGHT);
         mBrightnessEvent.setLux(100.0f);
         mBrightnessEvent.setPreThresholdLux(150.0f);
         mBrightnessEvent.setTime(System.currentTimeMillis());
@@ -55,6 +62,7 @@
         mBrightnessEvent.setAdjustmentFlags(0);
         mBrightnessEvent.setAutomaticBrightnessEnabled(true);
         mBrightnessEvent.setDisplayBrightnessStrategyName(DISPLAY_BRIGHTNESS_STRATEGY_NAME);
+        mBrightnessEvent.setAutoBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE);
     }
 
     @Test
@@ -69,20 +77,21 @@
     public void testToStringWorksAsExpected() {
         String actualString = mBrightnessEvent.toString(false);
         String expectedString =
-                "BrightnessEvent: disp=1, physDisp=test, brt=0.6, initBrt=25.0, rcmdBrt=0.6,"
-                + " preBrt=NaN, lux=100.0, preLux=150.0, hbmMax=0.62, hbmMode=off, rbcStrength=-1,"
-                + " thrmMax=0.65, powerFactor=0.2, wasShortTermModelActive=true, flags=,"
-                + " reason=doze [ low_pwr ], autoBrightness=true, strategy="
-                        + DISPLAY_BRIGHTNESS_STRATEGY_NAME;
+                "BrightnessEvent: disp=1, physDisp=test, displayState=ON, displayPolicy=BRIGHT,"
+                + " brt=0.6, initBrt=25.0, rcmdBrt=0.6, preBrt=NaN, lux=100.0, preLux=150.0,"
+                + " hbmMax=0.62, hbmMode=off, rbcStrength=-1, thrmMax=0.65, powerFactor=0.2,"
+                + " wasShortTermModelActive=true, flags=, reason=doze [ low_pwr ],"
+                + " autoBrightness=true, strategy=" + DISPLAY_BRIGHTNESS_STRATEGY_NAME
+                + ", autoBrightnessMode=idle";
         assertEquals(expectedString, actualString);
     }
 
     @Test
     public void testFlagsToString() {
         mBrightnessEvent.reset();
-        mBrightnessEvent.setFlags(mBrightnessEvent.getFlags() | BrightnessEvent.FLAG_IDLE_CURVE);
+        mBrightnessEvent.setFlags(mBrightnessEvent.getFlags() | BrightnessEvent.FLAG_RBC);
         String actualString = mBrightnessEvent.flagsToString();
-        String expectedString = "idle_curve ";
+        String expectedString = "rbc ";
         assertEquals(expectedString, actualString);
     }
 
@@ -90,10 +99,10 @@
     public void testFlagsToString_multipleFlags() {
         mBrightnessEvent.reset();
         mBrightnessEvent.setFlags(mBrightnessEvent.getFlags()
-                    | BrightnessEvent.FLAG_IDLE_CURVE
+                    | BrightnessEvent.FLAG_RBC
                     | BrightnessEvent.FLAG_LOW_POWER_MODE);
         String actualString = mBrightnessEvent.flagsToString();
-        String expectedString = "idle_curve low_power_mode ";
+        String expectedString = "rbc low_power_mode ";
         assertEquals(expectedString, actualString);
     }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
index 37958fa..1c681ce 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
@@ -27,6 +27,7 @@
 import android.content.ContextWrapper;
 import android.content.res.Resources;
 import android.hardware.display.DisplayManagerInternal;
+import android.os.PowerManager;
 import android.view.Display;
 
 import androidx.test.core.app.ApplicationProvider;
@@ -155,6 +156,7 @@
         DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
                 DisplayManagerInternal.DisplayPowerRequest.class);
         displayPowerRequest.policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+        displayPowerRequest.dozeScreenBrightness = 0.2f;
         when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
                 DISALLOW_AUTO_BRIGHTNESS_WHILE_DOZING);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest,
@@ -162,6 +164,18 @@
     }
 
     @Test
+    public void selectStrategyDoesNotSelectDozeStrategyWhenInvalidBrightness() {
+        DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
+                DisplayManagerInternal.DisplayPowerRequest.class);
+        displayPowerRequest.policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+        displayPowerRequest.dozeScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+        when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
+                DISALLOW_AUTO_BRIGHTNESS_WHILE_DOZING);
+        assertNotEquals(mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest,
+                Display.STATE_DOZE), mDozeBrightnessModeStrategy);
+    }
+
+    @Test
     public void selectStrategySelectsScreenOffStrategyWhenValid() {
         DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
                 DisplayManagerInternal.DisplayPowerRequest.class);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
index 5408e11..ba462e3 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
@@ -215,7 +215,7 @@
         mAutomaticBrightnessStrategy.setUseAutoBrightness(true);
         int targetDisplayState = Display.STATE_DOZE;
         boolean allowAutoBrightnessWhileDozing = true;
-        int brightnessReason = BrightnessReason.REASON_DOZE;
+        int brightnessReason = BrightnessReason.REASON_UNKNOWN;
         int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
         float lastUserSetBrightness = 0.2f;
         boolean userSetBrightnessChanged = true;
@@ -359,11 +359,17 @@
                 AutomaticBrightnessController.class);
         when(automaticBrightnessController.getAutomaticScreenBrightness(any(BrightnessEvent.class)))
                 .thenReturn(automaticScreenBrightness);
+        when(automaticBrightnessController.getAutomaticScreenBrightnessBasedOnLastObservedLux(
+                any(BrightnessEvent.class)))
+                .thenReturn(automaticScreenBrightness);
         mAutomaticBrightnessStrategy.setAutomaticBrightnessController(
                 automaticBrightnessController);
         assertEquals(automaticScreenBrightness,
                 mAutomaticBrightnessStrategy.getAutomaticScreenBrightness(
                         new BrightnessEvent(DISPLAY_ID)), 0.0f);
+        assertEquals(automaticScreenBrightness,
+                mAutomaticBrightnessStrategy.getAutomaticScreenBrightnessBasedOnLastObservedLux(
+                        new BrightnessEvent(DISPLAY_ID)), 0.0f);
     }
 
     @Test
diff --git a/services/tests/dreamservicetests/Android.bp b/services/tests/dreamservicetests/Android.bp
index 5aa5d61..86b3a6c 100644
--- a/services/tests/dreamservicetests/Android.bp
+++ b/services/tests/dreamservicetests/Android.bp
@@ -18,6 +18,11 @@
         "mockito-target-minus-junit4",
         "services.core",
         "mockingservicestests-utils-mockito",
+        "servicestests-utils",
+    ],
+
+    defaults: [
+        "modules-utils-testable-device-config-defaults",
     ],
 
     platform_apis: true,
diff --git a/services/tests/dreamservicetests/AndroidManifest.xml b/services/tests/dreamservicetests/AndroidManifest.xml
index f4b88d9..6092ef6 100644
--- a/services/tests/dreamservicetests/AndroidManifest.xml
+++ b/services/tests/dreamservicetests/AndroidManifest.xml
@@ -21,6 +21,7 @@
     Insert permissions here. eg:
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     -->
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
 
     <application android:debuggable="true"
                  android:testOnly="true">
diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamManagerServiceMockingTest.java b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamManagerServiceMockingTest.java
index 32d4e75..992b853 100644
--- a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamManagerServiceMockingTest.java
+++ b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamManagerServiceMockingTest.java
@@ -36,13 +36,14 @@
 import android.provider.Settings;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
 
-import com.android.server.LocalServices;
+import com.android.internal.util.test.LocalServiceKeeperRule;
 import com.android.server.SystemService;
+import com.android.server.testutils.TestHandler;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -65,23 +66,24 @@
     @Mock
     private UserManager mUserManagerMock;
 
-    private MockitoSession mMockitoSession;
+    @Rule
+    public LocalServiceKeeperRule mLocalServiceKeeperRule = new LocalServiceKeeperRule();
 
-    private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
-        LocalServices.removeServiceForTest(clazz);
-        LocalServices.addService(clazz, mock);
-    }
+    private TestHandler mTestHandler;
+    private MockitoSession mMockitoSession;
 
     @Before
     public void setUp() throws Exception {
+        mTestHandler = new TestHandler(/* callback= */ null);
         MockitoAnnotations.initMocks(this);
-
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
         mResourcesSpy = spy(mContextSpy.getResources());
         when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
 
-        addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock);
-        addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock);
+        mLocalServiceKeeperRule.overrideLocalService(
+                ActivityManagerInternal.class, mActivityManagerInternalMock);
+        mLocalServiceKeeperRule.overrideLocalService(
+                PowerManagerInternal.class, mPowerManagerInternalMock);
 
         when(mContextSpy.getSystemService(UserManager.class)).thenReturn(mUserManagerMock);
         mMockitoSession = mockitoSession()
@@ -94,26 +96,20 @@
     @After
     public void tearDown() throws Exception {
         mMockitoSession.finishMocking();
-        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
-        LocalServices.removeServiceForTest(PowerManagerInternal.class);
     }
 
     private DreamManagerService createService() {
-        return new DreamManagerService(mContextSpy);
+        return new DreamManagerService(mContextSpy, mTestHandler);
     }
 
     @Test
-    @FlakyTest(bugId = 293443309)
     public void testSettingsQueryUserChange() {
         final DreamManagerService service = createService();
-
         final SystemService.TargetUser from =
                 new SystemService.TargetUser(mock(UserInfo.class));
         final SystemService.TargetUser to =
                 new SystemService.TargetUser(mock(UserInfo.class));
-
         service.onUserSwitching(from, to);
-
         verify(() -> Settings.Secure.getIntForUser(any(),
                 eq(Settings.Secure.SCREENSAVER_ENABLED),
                 anyInt(),
diff --git a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java
index dad36e7..2366f56 100644
--- a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java
@@ -30,6 +30,7 @@
 import android.media.projection.MediaProjectionInfo;
 import android.media.projection.MediaProjectionManager;
 import android.os.Binder;
+import android.os.Process;
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -52,6 +53,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Set;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RequiresFlagsEnabled(FLAG_SENSITIVE_CONTENT_APP_PROTECTION)
@@ -62,12 +65,14 @@
 public class SensitiveContentProtectionManagerServiceContentTest {
     private final PackageInfo mPackageInfo =
             new PackageInfo("test.package", 12345, new Binder());
+    private final String mScreenRecorderPackage = "test.screen.recorder.package";
+    private final String mExemptedScreenRecorderPackage = "test.exempted.screen.recorder.package";
     private SensitiveContentProtectionManagerService mSensitiveContentProtectionManagerService;
     private MediaProjectionManager.Callback mMediaPorjectionCallback;
 
     @Mock private WindowManagerInternal mWindowManager;
     @Mock private MediaProjectionManager mProjectionManager;
-    @Mock private MediaProjectionInfo mMediaProjectionInfo;
+    private MediaProjectionInfo mMediaProjectionInfo;
 
     @Captor
     private ArgumentCaptor<MediaProjectionManager.Callback> mMediaProjectionCallbackCaptor;
@@ -85,9 +90,22 @@
         MockitoAnnotations.initMocks(this);
         mSensitiveContentProtectionManagerService =
                 new SensitiveContentProtectionManagerService(mContext);
-        mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager);
+        mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager,
+                new ArraySet<>(Set.of(mExemptedScreenRecorderPackage)));
         verify(mProjectionManager).addCallback(mMediaProjectionCallbackCaptor.capture(), any());
         mMediaPorjectionCallback = mMediaProjectionCallbackCaptor.getValue();
+        mMediaProjectionInfo =
+                new MediaProjectionInfo(mScreenRecorderPackage, Process.myUserHandle(), null);
+    }
+
+    @Test
+    public void testExemptedRecorderPackageForScreenCapture() {
+        MediaProjectionInfo exemptedRecorderPackage = new MediaProjectionInfo(
+                mExemptedScreenRecorderPackage, Process.myUserHandle(), null);
+        mMediaPorjectionCallback.onStart(exemptedRecorderPackage);
+        mSensitiveContentProtectionManagerService.setSensitiveContentProtection(
+                mPackageInfo.getWindowToken(), mPackageInfo.getPkg(), mPackageInfo.getUid(), true);
+        verifyZeroInteractions(mWindowManager);
     }
 
     @Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
index 08050a9..e74fe29 100644
--- a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
@@ -78,6 +78,8 @@
     private static final String NOTIFICATION_PKG_1 = "com.android.server.notification.one";
     private static final String NOTIFICATION_PKG_2 = "com.android.server.notification.two";
 
+    private static final String EXEMPTED_SCREEN_RECORDER_PACKAGE = "test.screen.recorder.package";
+
     private static final int NOTIFICATION_UID_1 = 5;
     private static final int NOTIFICATION_UID_2 = 6;
 
@@ -138,7 +140,8 @@
 
         setupSensitiveNotification();
 
-        mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager);
+        mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager,
+                new ArraySet<>(Set.of(EXEMPTED_SCREEN_RECORDER_PACKAGE)));
 
         // Obtain useful mMediaProjectionCallback
         verify(mProjectionManager).addCallback(mMediaProjectionCallbackCaptor.capture(), any());
@@ -275,6 +278,16 @@
     }
 
     @Test
+    public void mediaProjectionOnStart_verifyExemptedRecorderPackage() {
+        MediaProjectionInfo mediaProjectionInfo = mock(MediaProjectionInfo.class);
+        when(mediaProjectionInfo.getPackageName()).thenReturn(EXEMPTED_SCREEN_RECORDER_PACKAGE);
+
+        mMediaProjectionCallbackCaptor.getValue().onStart(mediaProjectionInfo);
+
+        verifyZeroInteractions(mWindowManager);
+    }
+
+    @Test
     public void mediaProjectionOnStart_onProjectionStart_setWmBlockedPackages() {
         ArraySet<PackageInfo> expectedBlockedPackages = setupSensitiveNotification();
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
index a8faa54..ad68de8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
@@ -196,6 +196,9 @@
         when(mMockResources.getBoolean(
                 com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled))
                 .thenReturn(false);
+        when(mMockResources.getBoolean(
+                com.android.internal.R.bool.config_batterySaverTurnedOffNotificationEnabled))
+                .thenReturn(true);
         when(mMockResources.getInteger(
                 com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold))
                 .thenReturn(80);
diff --git a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
index d6e246f..6e41685 100644
--- a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
@@ -25,6 +25,8 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -42,6 +44,7 @@
 import android.crashrecovery.flags.Flags;
 import android.os.Handler;
 import android.os.MessageQueue;
+import android.os.SystemProperties;
 import android.platform.test.flag.junit.SetFlagsRule;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -65,6 +68,7 @@
 import org.mockito.stubbing.Answer;
 
 import java.time.Duration;
+import java.util.HashMap;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -90,7 +94,7 @@
 
     @Rule
     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
-
+    private HashMap<String, String> mSystemSettingsMap;
     private MockitoSession mSession;
     private static final String APP_A = "com.package.a";
     private static final String APP_B = "com.package.b";
@@ -99,6 +103,9 @@
     private static final long VERSION_CODE_2 = 2L;
     private static final String LOG_TAG = "RollbackPackageHealthObserverTest";
 
+    private static final String PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG =
+            "persist.device_config.configuration.disable_high_impact_rollback";
+
     private SystemConfig mSysConfig;
 
     @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
@@ -111,11 +118,34 @@
                 .initMocks(this)
                 .strictness(Strictness.LENIENT)
                 .spyStatic(PackageWatchdog.class)
+                .spyStatic(SystemProperties.class)
                 .startMocking();
+        mSystemSettingsMap = new HashMap<>();
 
         // Mock PackageWatchdog
         doAnswer((Answer<PackageWatchdog>) invocationOnMock -> mMockPackageWatchdog)
                 .when(() -> PackageWatchdog.getInstance(mMockContext));
+
+        // Mock SystemProperties setter and various getters
+        doAnswer((Answer<Void>) invocationOnMock -> {
+                    String key = invocationOnMock.getArgument(0);
+                    String value = invocationOnMock.getArgument(1);
+
+                    mSystemSettingsMap.put(key, value);
+                    return null;
+                }
+        ).when(() -> SystemProperties.set(anyString(), anyString()));
+
+        doAnswer((Answer<Boolean>) invocationOnMock -> {
+                    String key = invocationOnMock.getArgument(0);
+                    boolean defaultValue = invocationOnMock.getArgument(1);
+
+                    String storedValue = mSystemSettingsMap.get(key);
+                    return storedValue == null ? defaultValue : Boolean.parseBoolean(storedValue);
+                }
+        ).when(() -> SystemProperties.getBoolean(anyString(), anyBoolean()));
+
+        SystemProperties.set(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, Boolean.toString(false));
     }
 
     @After
@@ -609,6 +639,32 @@
                 observer.onBootLoop(1));
     }
 
+    @Test
+    public void onBootLoop_impactLevelHighDisableHighImpactRollback_onePackage()
+            throws PackageManager.NameNotFoundException {
+        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+        SystemProperties.set(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, Boolean.toString(true));
+        VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2);
+        VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE);
+        PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(appAFrom, appATo,
+                null, null, false, false,
+                null);
+        RollbackInfo rollbackInfo1 = new RollbackInfo(1, List.of(packageRollbackInfo),
+                false, null, 111,
+                PackageManager.ROLLBACK_USER_IMPACT_HIGH);
+        RollbackPackageHealthObserver observer =
+                spy(new RollbackPackageHealthObserver(mMockContext, mApexManager));
+
+        when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
+        // Make the rollbacks available
+        when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(rollbackInfo1));
+        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+        when(mMockPackageManager.getModuleInfo(any(), eq(0))).thenReturn(null);
+
+        assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_0,
+                observer.onBootLoop(1));
+    }
+
     /**
      * When the rollback impact level is manual only return user impact level 0. (User impact level
      * 0 is ignored by package watchdog)
@@ -924,6 +980,50 @@
         assertThat(argument.getAllValues()).isEqualTo(List.of(rollbackId2));
     }
 
+    /**
+     * Don't roll back if kill switch is enabled.
+     */
+    @Test
+    public void executeBootLoopMitigation_impactLevelHighKillSwitchTrue_rollbackHigh()
+            throws PackageManager.NameNotFoundException {
+        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+        SystemProperties.set(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, Boolean.toString(true));
+        int rollbackId1 = 1;
+        VersionedPackage appBFrom = new VersionedPackage(APP_B, VERSION_CODE_2);
+        VersionedPackage appBTo = new VersionedPackage(APP_B, VERSION_CODE);
+        PackageRollbackInfo packageRollbackInfoB = new PackageRollbackInfo(appBFrom, appBTo,
+                null, null , false, false,
+                null);
+        RollbackInfo rollbackInfo1 = new RollbackInfo(rollbackId1, List.of(packageRollbackInfoB),
+                false, null, 111,
+                PackageManager.ROLLBACK_USER_IMPACT_HIGH);
+        int rollbackId2 = 2;
+        VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2);
+        VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE);
+        PackageRollbackInfo packageRollbackInfoA = new PackageRollbackInfo(appAFrom, appATo,
+                null, null , false, false,
+                null);
+        RollbackInfo rollbackInfo2 = new RollbackInfo(rollbackId2, List.of(packageRollbackInfoA),
+                false, null, 111,
+                PackageManager.ROLLBACK_USER_IMPACT_HIGH);
+        RollbackPackageHealthObserver observer =
+                spy(new RollbackPackageHealthObserver(mMockContext, mApexManager));
+        ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
+
+        when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
+        // Make the rollbacks available
+        when(mRollbackManager.getAvailableRollbacks()).thenReturn(
+                List.of(rollbackInfo1, rollbackInfo2));
+        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+        when(mMockPackageManager.getModuleInfo(any(), eq(0))).thenReturn(null);
+
+        observer.executeBootLoopMitigation(1);
+        waitForIdleHandler(observer.getHandler(), Duration.ofSeconds(10));
+
+        verify(mRollbackManager, never()).commitRollback(
+                argument.capture(), any(), any());
+    }
+
     private void waitForIdleHandler(Handler handler, Duration timeout) {
         final MessageQueue queue = handler.getLooper().getQueue();
         final CountDownLatch latch = new CountDownLatch(1);
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 3743483..37967fa 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -85,6 +85,7 @@
         "ravenwood-junit",
         "net_flags_lib",
         "CtsVirtualDeviceCommonLib",
+        "com_android_server_accessibility_flags_lib",
     ],
 
     libs: [
diff --git a/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java b/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
index d367f71..4a8fe41 100644
--- a/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
@@ -19,7 +19,8 @@
 import android.os.ServiceManager;
 import android.os.image.IDynamicSystemService;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 public class DynamicSystemServiceTest extends AndroidTestCase {
     private static final String TAG = "DynamicSystemServiceTests";
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt
index 5c8c6bb..e6c94c5 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt
@@ -25,6 +25,7 @@
 import android.view.DisplayAdjustments
 import android.view.DisplayInfo
 import android.view.IInputFilterHost
+import android.view.InputDevice.SOURCE_JOYSTICK
 import android.view.InputDevice.SOURCE_STYLUS
 import android.view.InputDevice.SOURCE_TOUCHSCREEN
 import android.view.InputEvent
@@ -130,6 +131,8 @@
     private val fromTouchScreen = allOf(withDeviceId(touchDeviceId), withSource(SOURCE_TOUCHSCREEN))
     private val stylusDeviceId = 2
     private val fromStylus = allOf(withDeviceId(stylusDeviceId), withSource(STYLUS_SOURCE))
+    private val joystickDeviceId = 3
+    private val fromJoystick = allOf(withDeviceId(joystickDeviceId), withSource(SOURCE_JOYSTICK))
 
     @Before
     fun setUp() {
@@ -457,6 +460,23 @@
         verifier.assertNoEvents()
     }
 
+    /**
+     * Send some joystick events and ensure they pass through normally.
+     */
+    @Test
+    fun testJoystickEvents() {
+        enableFeatures(ALL_A11Y_FEATURES)
+
+        sendJoystickEvent()
+        verifier.assertReceivedMotion(fromJoystick)
+
+        sendJoystickEvent()
+        verifier.assertReceivedMotion(fromJoystick)
+
+        sendJoystickEvent()
+        verifier.assertReceivedMotion(fromJoystick)
+    }
+
     private fun createStubDisplay(displayId: Int, displayInfo: DisplayInfo): Display {
         val display = Display(DisplayManagerGlobal.getInstance(), displayId,
             displayInfo, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS)
@@ -477,6 +497,11 @@
         send(createMotionEvent(action, downTime, eventTime, STYLUS_SOURCE, stylusDeviceId))
     }
 
+    private fun sendJoystickEvent() {
+        val time = SystemClock.uptimeMillis()
+        send(createMotionEvent(ACTION_MOVE, time, time, SOURCE_JOYSTICK, joystickDeviceId))
+    }
+
     private fun send(event: InputEvent) {
         // We need to make a copy of the event before sending it to the filter, because the filter
         // will recycle it, but the caller of this function might want to still be able to use
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
index 89d146d..8717a05 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -47,6 +47,9 @@
 import android.os.LocaleList;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.IWindow;
@@ -67,6 +70,7 @@
 import org.hamcrest.TypeSafeMatcher;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
@@ -77,9 +81,16 @@
 import java.util.Arrays;
 import java.util.List;
 
+// This test verifies deprecated codepath. Probably changing this file means
+// AccessibilityWindowManagerWithAccessibilityWindowTest also needs to be updated.
+// LINT.IfChange
+
 /**
- * Tests for the AccessibilityWindowManager
+ * Tests for the AccessibilityWindowManager with Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y enabled.
+ * TODO(b/322444245): Merge with AccessibilityWindowManagerWithAccessibilityWindowTest
+ *  after completing the flag migration.
  */
+@RequiresFlagsDisabled(Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y)
 public class AccessibilityWindowManagerTest {
     private static final String PACKAGE_NAME = "com.android.server.accessibility";
     private static final boolean FORCE_SEND = true;
@@ -132,6 +143,9 @@
     @Mock private IBinder mMockEmbeddedToken;
     @Mock private IBinder mMockInvalidToken;
 
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
     @Before
     public void setUp() throws RemoteException {
         MockitoAnnotations.initMocks(this);
@@ -1227,3 +1241,4 @@
         }
     }
 }
+// LINT.ThenChange(/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java)
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java
new file mode 100644
index 0000000..4db27d2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java
@@ -0,0 +1,1247 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility;
+
+import static com.android.server.accessibility.AbstractAccessibilityServiceConnection.DISPLAY_TYPE_DEFAULT;
+import static com.android.server.accessibility.AccessibilityWindowManagerTest.DisplayIdMatcher.displayId;
+import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowChangesMatcher.a11yWindowChanges;
+import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowIdMatcher.a11yWindowId;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.Nullable;
+import android.graphics.Region;
+import android.os.IBinder;
+import android.os.LocaleList;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.IWindow;
+import android.view.WindowInfo;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityWindowAttributes;
+import android.view.accessibility.AccessibilityWindowInfo;
+import android.view.accessibility.IAccessibilityInteractionConnection;
+
+import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
+import com.android.server.accessibility.test.MessageCapturingHandler;
+import com.android.server.wm.WindowManagerInternal;
+import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
+
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests for the AccessibilityWindowManager with Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y
+ * TODO(b/322444245): Merge with AccessibilityWindowManagerTest
+ *  after completing the flag migration.
+ */
+@RequiresFlagsEnabled(Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y)
+public class AccessibilityWindowManagerWithAccessibilityWindowTest {
+    private static final String PACKAGE_NAME = "com.android.server.accessibility";
+    private static final boolean FORCE_SEND = true;
+    private static final boolean SEND_ON_WINDOW_CHANGES = false;
+    private static final int USER_SYSTEM_ID = UserHandle.USER_SYSTEM;
+    private static final int USER_PROFILE = 11;
+    private static final int USER_PROFILE_PARENT = 1;
+    private static final int SECONDARY_DISPLAY_ID = Display.DEFAULT_DISPLAY + 1;
+    private static final int NUM_GLOBAL_WINDOWS = 4;
+    private static final int NUM_APP_WINDOWS = 4;
+    private static final int NUM_OF_WINDOWS = (NUM_GLOBAL_WINDOWS + NUM_APP_WINDOWS);
+    private static final int DEFAULT_FOCUSED_INDEX = 1;
+    private static final int SCREEN_WIDTH = 1080;
+    private static final int SCREEN_HEIGHT = 1920;
+    private static final int INVALID_ID = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
+    private static final int HOST_WINDOW_ID = 10;
+    private static final int EMBEDDED_WINDOW_ID = 11;
+    private static final int OTHER_WINDOW_ID = 12;
+
+    private AccessibilityWindowManager mA11yWindowManager;
+    // Window manager will support multiple focused window if config_perDisplayFocusEnabled is true,
+    // i.e., each display would have its current focused window, and one of all focused windows
+    // would be top focused window. Otherwise, window manager only supports one focused window
+    // at all displays, and that focused window would be top focused window.
+    private boolean mSupportPerDisplayFocus = false;
+    private int mTopFocusedDisplayId = Display.INVALID_DISPLAY;
+    private IBinder mTopFocusedWindowToken = null;
+
+    // List of window token, mapping from windowId -> window token.
+    private final SparseArray<IWindow> mA11yWindowTokens = new SparseArray<>();
+    // List of window info lists, mapping from displayId -> window info lists.
+    private final SparseArray<ArrayList<WindowInfo>> mWindowInfos =
+            new SparseArray<>();
+    // List of callback, mapping from displayId -> callback.
+    private final SparseArray<WindowsForAccessibilityCallback> mCallbackOfWindows =
+            new SparseArray<>();
+    // List of display ID.
+    private final ArrayList<Integer> mExpectedDisplayList = new ArrayList<>(Arrays.asList(
+            Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID));
+
+    private final MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
+
+    @Mock
+    private WindowManagerInternal mMockWindowManagerInternal;
+    @Mock
+    private AccessibilityWindowManager.AccessibilityEventSender mMockA11yEventSender;
+    @Mock
+    private AccessibilitySecurityPolicy mMockA11ySecurityPolicy;
+    @Mock
+    private AccessibilitySecurityPolicy.AccessibilityUserManager mMockA11yUserManager;
+    @Mock
+    private AccessibilityTraceManager mMockA11yTraceManager;
+
+    @Mock
+    private IBinder mMockHostToken;
+    @Mock
+    private IBinder mMockEmbeddedToken;
+    @Mock
+    private IBinder mMockInvalidToken;
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+    @Before
+    public void setUp() throws RemoteException {
+        MockitoAnnotations.initMocks(this);
+        when(mMockA11yUserManager.getCurrentUserIdLocked()).thenReturn(USER_SYSTEM_ID);
+        when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
+                USER_PROFILE)).thenReturn(USER_PROFILE_PARENT);
+        when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
+                USER_SYSTEM_ID)).thenReturn(USER_SYSTEM_ID);
+        when(mMockA11ySecurityPolicy.resolveValidReportedPackageLocked(
+                anyString(), anyInt(), anyInt(), anyInt())).thenReturn(PACKAGE_NAME);
+
+        doAnswer((invocation) -> {
+            onWindowsForAccessibilityChanged(invocation.getArgument(0), false);
+            return null;
+        }).when(mMockWindowManagerInternal).computeWindowsForAccessibility(anyInt());
+
+        mA11yWindowManager = new AccessibilityWindowManager(new Object(), mHandler,
+                mMockWindowManagerInternal,
+                mMockA11yEventSender,
+                mMockA11ySecurityPolicy,
+                mMockA11yUserManager,
+                mMockA11yTraceManager);
+        // Starts tracking window of default display and sets the default display
+        // as top focused display before each testing starts.
+        startTrackingPerDisplay(Display.DEFAULT_DISPLAY);
+
+        // AccessibilityEventSender is invoked during onWindowsForAccessibilityChanged.
+        // Resets it for mockito verify of further test case.
+        Mockito.reset(mMockA11yEventSender);
+
+        registerLeashedTokenAndWindowId();
+    }
+
+    @After
+    public void tearDown() {
+        mHandler.removeAllMessages();
+    }
+
+    @Test
+    public void startTrackingWindows_shouldEnableWindowManagerCallback() {
+        // AccessibilityWindowManager#startTrackingWindows already invoked in setup.
+        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
+        final WindowsForAccessibilityCallback callbacks =
+                mCallbackOfWindows.get(Display.DEFAULT_DISPLAY);
+        verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
+                eq(Display.DEFAULT_DISPLAY), eq(callbacks));
+    }
+
+    @Test
+    public void stopTrackingWindows_shouldDisableWindowManagerCallback() {
+        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
+        Mockito.reset(mMockWindowManagerInternal);
+
+        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
+        assertFalse(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
+        verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
+                eq(Display.DEFAULT_DISPLAY), isNull());
+
+    }
+
+    @Test
+    public void stopTrackingWindows_shouldClearWindows() {
+        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
+        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+
+        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
+        assertNull(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY));
+        assertEquals(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
+                AccessibilityWindowInfo.UNDEFINED_WINDOW_ID);
+        assertEquals(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID),
+                activeWindowId);
+    }
+
+    @Test
+    public void stopTrackingWindows_onNonTopFocusedDisplay_shouldNotResetTopFocusWindow()
+            throws RemoteException {
+        // At setup, the default display sets be the top focused display and
+        // its current focused window sets be the top focused window.
+        // Starts tracking window of second display.
+        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
+        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID));
+        // Stops tracking windows of second display.
+        mA11yWindowManager.stopTrackingWindows(SECONDARY_DISPLAY_ID);
+        assertNotEquals(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
+                AccessibilityWindowInfo.UNDEFINED_WINDOW_ID);
+    }
+
+    @Test
+    public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() {
+        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+        WindowInfo focusedWindowInfo =
+                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX);
+        assertEquals(activeWindowId, mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, focusedWindowInfo.token));
+
+        focusedWindowInfo.focused = false;
+        focusedWindowInfo =
+                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1);
+        focusedWindowInfo.focused = true;
+
+        mA11yWindowManager.onTouchInteractionStart();
+        setTopFocusedWindowAndDisplay(Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX + 1);
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
+    }
+
+    @Test
+    public void
+            onWindowsChanged_focusChangeOnNonTopFocusedDisplay_perDisplayFocusOn_notChangeWindow()
+            throws RemoteException {
+        // At setup, the default display sets be the top focused display and
+        // its current focused window sets be the top focused window.
+        // Sets supporting multiple focused window, i.e., config_perDisplayFocusEnabled is true.
+        mSupportPerDisplayFocus = true;
+        // Starts tracking window of second display.
+        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
+        // Gets the active window.
+        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+        // Gets the top focused window.
+        final int topFocusedWindowId =
+                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT);
+        // Changes the current focused window at second display.
+        changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
+                DEFAULT_FOCUSED_INDEX + 1, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
+
+        onWindowsForAccessibilityChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
+        // The active window should not be changed.
+        assertEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
+        // The top focused window should not be changed.
+        assertEquals(topFocusedWindowId,
+                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT));
+    }
+
+    @Test
+    public void
+            onWindowChange_focusChangeToNonTopFocusedDisplay_perDisplayFocusOff_shouldChangeWindow()
+            throws RemoteException {
+        // At setup, the default display sets be the top focused display and
+        // its current focused window sets be the top focused window.
+        // Sets not supporting multiple focused window, i.e., config_perDisplayFocusEnabled is
+        // false.
+        mSupportPerDisplayFocus = false;
+        // Starts tracking window of second display.
+        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
+        // Gets the active window.
+        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+        // Gets the top focused window.
+        final int topFocusedWindowId =
+                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT);
+        // Changes the current focused window from default display to second display.
+        changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
+                DEFAULT_FOCUSED_INDEX, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        onWindowsForAccessibilityChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
+        // The active window should be changed.
+        assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
+        // The top focused window should be changed.
+        assertNotEquals(topFocusedWindowId,
+                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT));
+    }
+
+    @Test
+    public void onWindowsChanged_shouldReportCorrectLayer() {
+        // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup.
+        List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        for (int i = 0; i < a11yWindows.size(); i++) {
+            final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
+            final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i);
+            assertThat(mWindowInfos.get(Display.DEFAULT_DISPLAY).size() - windowInfo.layer - 1,
+                    is(a11yWindow.getLayer()));
+        }
+    }
+
+    @Test
+    public void onWindowsChanged_shouldReportCorrectOrder() {
+        // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup.
+        List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        for (int i = 0; i < a11yWindows.size(); i++) {
+            final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
+            final IBinder windowToken = mA11yWindowManager
+                    .getWindowTokenForUserAndWindowIdLocked(USER_SYSTEM_ID, a11yWindow.getId());
+            final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i);
+            assertThat(windowToken, is(windowInfo.token));
+        }
+    }
+
+    @Test
+    public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
+        final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+        final int correctLayer =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer();
+        windowInfo.layer += 1;
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+        assertNotEquals(correctLayer,
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer());
+    }
+
+    @Test
+    public void onWindowsChangedNoForceSend_layerChanged_shouldNotUpdateWindows() {
+        final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+        final int correctLayer =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer();
+        windowInfo.layer += 1;
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        assertEquals(correctLayer,
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer());
+    }
+
+    @Test
+    public void onWindowsChangedNoForceSend_windowChanged_shouldUpdateWindows()
+            throws RemoteException {
+        final AccessibilityWindowInfo oldWindow =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0);
+        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                true, USER_SYSTEM_ID);
+        final WindowInfo windowInfo = WindowInfo.obtain();
+        windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
+        windowInfo.token = token.asBinder();
+        windowInfo.layer = 0;
+        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+        mWindowInfos.get(Display.DEFAULT_DISPLAY).set(0, windowInfo);
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        assertNotEquals(oldWindow,
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0));
+    }
+
+    @Test
+    public void onWindowsChangedNoForceSend_focusChanged_shouldUpdateWindows() {
+        final WindowInfo focusedWindowInfo =
+                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX);
+        final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+        focusedWindowInfo.focused = false;
+        windowInfo.focused = true;
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        assertTrue(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0)
+                .isFocused());
+    }
+
+    @Test
+    public void removeAccessibilityInteractionConnection_byWindowToken_shouldRemoved() {
+        for (int i = 0; i < NUM_OF_WINDOWS; i++) {
+            final int windowId = mA11yWindowTokens.keyAt(i);
+            final IWindow windowToken = mA11yWindowTokens.valueAt(i);
+            assertNotNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
+
+            mA11yWindowManager.removeAccessibilityInteractionConnection(windowToken);
+            assertNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
+        }
+    }
+
+    @Test
+    public void remoteAccessibilityConnection_binderDied_shouldRemoveConnection() {
+        for (int i = 0; i < NUM_OF_WINDOWS; i++) {
+            final int windowId = mA11yWindowTokens.keyAt(i);
+            final RemoteAccessibilityConnection remoteA11yConnection =
+                    mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId);
+            assertNotNull(remoteA11yConnection);
+
+            remoteA11yConnection.binderDied();
+            assertNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
+        }
+    }
+
+    @Test
+    public void getWindowTokenForUserAndWindowId_shouldNotNull() {
+        final List<AccessibilityWindowInfo> windows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        for (int i = 0; i < windows.size(); i++) {
+            final int windowId = windows.get(i).getId();
+
+            assertNotNull(mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
+                    USER_SYSTEM_ID, windowId));
+        }
+    }
+
+    @Test
+    public void findWindowId() {
+        final List<AccessibilityWindowInfo> windows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        for (int i = 0; i < windows.size(); i++) {
+            final int windowId = windows.get(i).getId();
+            final IBinder windowToken = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
+                    USER_SYSTEM_ID, windowId);
+
+            assertEquals(mA11yWindowManager.findWindowIdLocked(
+                    USER_SYSTEM_ID, windowToken), windowId);
+        }
+    }
+
+    @Test
+    public void resolveParentWindowId_windowIsNotEmbedded_shouldReturnGivenId()
+            throws RemoteException {
+        final int windowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, false,
+                Mockito.mock(IBinder.class), USER_SYSTEM_ID);
+        assertEquals(windowId, mA11yWindowManager.resolveParentWindowIdLocked(windowId));
+    }
+
+    @Test
+    public void resolveParentWindowId_windowIsNotRegistered_shouldReturnGivenId() {
+        final int windowId = -1;
+        assertEquals(windowId, mA11yWindowManager.resolveParentWindowIdLocked(windowId));
+    }
+
+    @Test
+    public void resolveParentWindowId_windowIsAssociated_shouldReturnParentWindowId()
+            throws RemoteException {
+        final IBinder mockHostToken = Mockito.mock(IBinder.class);
+        final IBinder mockEmbeddedToken = Mockito.mock(IBinder.class);
+        final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, mockHostToken, USER_SYSTEM_ID);
+        final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, mockEmbeddedToken, USER_SYSTEM_ID);
+
+        mA11yWindowManager.associateEmbeddedHierarchyLocked(mockHostToken, mockEmbeddedToken);
+
+        final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked(
+                embeddedWindowId);
+        assertEquals(hostWindowId, resolvedWindowId);
+    }
+
+    @Test
+    public void resolveParentWindowId_windowIsDisassociated_shouldReturnGivenId()
+            throws RemoteException {
+        final IBinder mockHostToken = Mockito.mock(IBinder.class);
+        final IBinder mockEmbeddedToken = Mockito.mock(IBinder.class);
+        final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, mockHostToken, USER_SYSTEM_ID);
+        final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, mockEmbeddedToken, USER_SYSTEM_ID);
+
+        mA11yWindowManager.associateEmbeddedHierarchyLocked(mockHostToken, mockEmbeddedToken);
+        mA11yWindowManager.disassociateEmbeddedHierarchyLocked(mockEmbeddedToken);
+
+        final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked(
+                embeddedWindowId);
+        assertNotEquals(hostWindowId, resolvedWindowId);
+        assertEquals(embeddedWindowId, resolvedWindowId);
+    }
+
+    @Test
+    public void computePartialInteractiveRegionForWindow_wholeVisible_returnWholeRegion() {
+        // Updates top 2 z-order WindowInfo are whole visible.
+        WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
+        windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1);
+        windowInfo.regionInScreen.set(0, SCREEN_HEIGHT / 2,
+                SCREEN_WIDTH, SCREEN_HEIGHT);
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        final Region outBounds = new Region();
+        int windowId = a11yWindows.get(0).getId();
+
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
+        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
+        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
+
+        windowId = a11yWindows.get(1).getId();
+
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
+        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
+        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
+    }
+
+    @Test
+    public void computePartialInteractiveRegionForWindow_halfVisible_returnHalfRegion() {
+        // Updates z-order #1 WindowInfo is half visible.
+        WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        final Region outBounds = new Region();
+        int windowId = a11yWindows.get(1).getId();
+
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
+        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
+        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
+    }
+
+    @Test
+    public void computePartialInteractiveRegionForWindow_notVisible_returnEmptyRegion() {
+        // Since z-order #0 WindowInfo is full screen, z-order #1 WindowInfo should be invisible.
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        final Region outBounds = new Region();
+        int windowId = a11yWindows.get(1).getId();
+
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
+        assertTrue(outBounds.getBounds().isEmpty());
+    }
+
+    @Test
+    public void computePartialInteractiveRegionForWindow_partialVisible_returnVisibleRegion() {
+        // Updates z-order #0 WindowInfo to have two interact-able areas.
+        Region region = new Region(0, 0, SCREEN_WIDTH, 200);
+        region.op(0, SCREEN_HEIGHT - 200, SCREEN_WIDTH, SCREEN_HEIGHT, Region.Op.UNION);
+        WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+        windowInfo.regionInScreen.set(region);
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        final Region outBounds = new Region();
+        int windowId = a11yWindows.get(1).getId();
+
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
+        assertFalse(outBounds.getBounds().isEmpty());
+        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
+        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT - 400));
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_windowStateChangedEvent_noTracking_shouldUpdate() {
+        final IBinder eventWindowToken =
+                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1).token;
+        final int eventWindowId = mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, eventWindowToken);
+        when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates())
+                .thenReturn(eventWindowToken);
+
+        final int noUse = 0;
+        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                noUse,
+                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
+                noUse);
+        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
+        assertThat(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
+                is(eventWindowId));
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_hoverEvent_touchInteract_shouldSetActiveWindow() {
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX + 1);
+        final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+        assertThat(currentActiveWindowId, is(not(eventWindowId)));
+
+        final int noUse = 0;
+        mA11yWindowManager.onTouchInteractionStart();
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                noUse,
+                AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
+                noUse);
+        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(2))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(currentActiveWindowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
+        assertThat(captor.getAllValues().get(1),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(eventWindowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_shouldUpdateA11yFocus() {
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX);
+        final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
+        assertThat(currentA11yFocusedWindowId, is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID));
+
+        final int noUse = 0;
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID,
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+                noUse);
+        assertThat(mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(1))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(eventWindowId),
+                        a11yWindowChanges(
+                                AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_multiDisplay_defaultToSecondary()
+            throws RemoteException {
+        runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
+                Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID);
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_multiDisplay_SecondaryToDefault()
+            throws RemoteException {
+        runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
+                SECONDARY_DISPLAY_ID, Display.DEFAULT_DISPLAY);
+    }
+
+    private void runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
+            int initialDisplayId, int eventDisplayId) throws RemoteException {
+        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
+        final int initialWindowId = getWindowIdFromWindowInfosForDisplay(
+                initialDisplayId, DEFAULT_FOCUSED_INDEX);
+        final int noUse = 0;
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                initialWindowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID,
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+                noUse);
+        assertThat(mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(initialWindowId));
+        Mockito.reset(mMockA11yEventSender);
+
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(
+                eventDisplayId, DEFAULT_FOCUSED_INDEX);
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID,
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+                noUse);
+        assertThat(mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(2))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(initialDisplayId),
+                        a11yWindowId(initialWindowId),
+                        a11yWindowChanges(
+                                AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
+        assertThat(captor.getAllValues().get(1),
+                allOf(displayId(eventDisplayId),
+                        a11yWindowId(eventWindowId),
+                        a11yWindowChanges(
+                                AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_clearA11yFocusEvent_shouldClearA11yFocus() {
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX);
+        final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
+        assertThat(currentA11yFocusedWindowId, is(not(eventWindowId)));
+
+        final int noUse = 0;
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID,
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+                noUse);
+        assertThat(mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID,
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED,
+                noUse);
+        assertThat(mA11yWindowManager.getFocusedWindowId(
+                        AccessibilityNodeInfo.FOCUS_ACCESSIBILITY),
+                is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID));
+    }
+
+    @Test
+    public void onTouchInteractionEnd_shouldRollbackActiveWindow() {
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX + 1);
+        final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+        assertThat(currentActiveWindowId, is(not(eventWindowId)));
+
+        final int noUse = 0;
+        mA11yWindowManager.onTouchInteractionStart();
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                noUse,
+                AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
+                noUse);
+        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
+        // AccessibilityEventSender is invoked after active window changed. Reset it.
+        Mockito.reset(mMockA11yEventSender);
+
+        mA11yWindowManager.onTouchInteractionEnd();
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(2))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(eventWindowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
+        assertThat(captor.getAllValues().get(1),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(currentActiveWindowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
+    }
+
+    @Test
+    public void onTouchInteractionEnd_noServiceInteractiveWindow_shouldClearA11yFocus()
+            throws RemoteException {
+        final IBinder defaultFocusWinToken =
+                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).token;
+        final int defaultFocusWindowId = mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, defaultFocusWinToken);
+        when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates())
+                .thenReturn(defaultFocusWinToken);
+        final int newFocusWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX + 1);
+        final IAccessibilityInteractionConnection mockNewFocusConnection =
+                mA11yWindowManager.getConnectionLocked(
+                        USER_SYSTEM_ID, newFocusWindowId).getRemote();
+
+        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
+        final int noUse = 0;
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                defaultFocusWindowId,
+                noUse,
+                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
+                noUse);
+        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(defaultFocusWindowId));
+        assertThat(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
+                is(defaultFocusWindowId));
+
+        mA11yWindowManager.onTouchInteractionStart();
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                newFocusWindowId,
+                noUse,
+                AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
+                noUse);
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                newFocusWindowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID,
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+                noUse);
+        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(newFocusWindowId));
+        assertThat(mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(newFocusWindowId));
+
+        mA11yWindowManager.onTouchInteractionEnd();
+        mHandler.sendLastMessage();
+        verify(mockNewFocusConnection).clearAccessibilityFocus();
+    }
+
+    @Test
+    public void getPictureInPictureWindow_shouldNotNull() {
+        assertNull(mA11yWindowManager.getPictureInPictureWindowLocked());
+        mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1).inPictureInPicture = true;
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        assertNotNull(mA11yWindowManager.getPictureInPictureWindowLocked());
+    }
+
+    @Test
+    public void notifyOutsideTouch() throws RemoteException {
+        final int targetWindowId =
+                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 1);
+        final int outsideWindowId =
+                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
+        final IAccessibilityInteractionConnection mockRemoteConnection =
+                mA11yWindowManager.getConnectionLocked(
+                        USER_SYSTEM_ID, outsideWindowId).getRemote();
+        mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0).hasFlagWatchOutsideTouch = true;
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        mA11yWindowManager.notifyOutsideTouch(USER_SYSTEM_ID, targetWindowId);
+        verify(mockRemoteConnection).notifyOutsideTouch();
+    }
+
+    @Test
+    public void addAccessibilityInteractionConnection_profileUser_findInParentUser()
+            throws RemoteException {
+        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, USER_PROFILE);
+        final int windowId = mA11yWindowManager.findWindowIdLocked(
+                USER_PROFILE_PARENT, token.asBinder());
+        assertTrue(windowId >= 0);
+    }
+
+    @Test
+    public void getDisplayList() throws RemoteException {
+        // Starts tracking window of second display.
+        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
+
+        final ArrayList<Integer> displayList = mA11yWindowManager.getDisplayListLocked(
+                DISPLAY_TYPE_DEFAULT);
+        assertTrue(displayList.equals(mExpectedDisplayList));
+    }
+
+    @Test
+    public void setAccessibilityWindowIdToSurfaceMetadata()
+            throws RemoteException {
+        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                true, USER_SYSTEM_ID);
+        int windowId = -1;
+        for (int i = 0; i < mA11yWindowTokens.size(); i++) {
+            if (mA11yWindowTokens.valueAt(i).equals(token)) {
+                windowId = mA11yWindowTokens.keyAt(i);
+            }
+        }
+        assertNotEquals("Returned token is not found in mA11yWindowTokens", -1, windowId);
+        verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata(
+                token.asBinder(), windowId);
+
+        mA11yWindowManager.removeAccessibilityInteractionConnection(token);
+        verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata(
+                token.asBinder(), -1);
+    }
+
+    @Test
+    public void getHostTokenLocked_hierarchiesAreAssociated_shouldReturnHostToken() {
+        mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
+        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
+        assertEquals(hostToken, mMockHostToken);
+    }
+
+    @Test
+    public void getHostTokenLocked_hierarchiesAreNotAssociated_shouldReturnNull() {
+        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
+        assertNull(hostToken);
+    }
+
+    @Test
+    public void getHostTokenLocked_embeddedHierarchiesAreDisassociated_shouldReturnNull() {
+        mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
+        mA11yWindowManager.disassociateLocked(mMockEmbeddedToken);
+        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
+        assertNull(hostToken);
+    }
+
+    @Test
+    public void getHostTokenLocked_hostHierarchiesAreDisassociated_shouldReturnNull() {
+        mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
+        mA11yWindowManager.disassociateLocked(mMockHostToken);
+        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockHostToken);
+        assertNull(hostToken);
+    }
+
+    @Test
+    public void getWindowIdLocked_windowIsRegistered_shouldReturnWindowId() {
+        final int windowId = mA11yWindowManager.getWindowIdLocked(mMockHostToken);
+        assertEquals(windowId, HOST_WINDOW_ID);
+    }
+
+    @Test
+    public void getWindowIdLocked_windowIsNotRegistered_shouldReturnInvalidWindowId() {
+        final int windowId = mA11yWindowManager.getWindowIdLocked(mMockInvalidToken);
+        assertEquals(windowId, INVALID_ID);
+    }
+
+    @Test
+    public void getTokenLocked_windowIsRegistered_shouldReturnToken() {
+        final IBinder token = mA11yWindowManager.getLeashTokenLocked(HOST_WINDOW_ID);
+        assertEquals(token, mMockHostToken);
+    }
+
+    @Test
+    public void getTokenLocked_windowIsNotRegistered_shouldReturnNull() {
+        final IBinder token = mA11yWindowManager.getLeashTokenLocked(OTHER_WINDOW_ID);
+        assertNull(token);
+    }
+
+    @Test
+    public void setAccessibilityWindowAttributes_windowIsNotRegistered_titleIsChanged() {
+        final int windowId =
+                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
+        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+        layoutParams.accessibilityTitle = "accessibility window title";
+        final AccessibilityWindowAttributes attributes = new AccessibilityWindowAttributes(
+                layoutParams, new LocaleList());
+
+        mA11yWindowManager.setAccessibilityWindowAttributes(Display.DEFAULT_DISPLAY, windowId,
+                USER_SYSTEM_ID, attributes);
+
+        final AccessibilityWindowInfo a11yWindow = mA11yWindowManager.findA11yWindowInfoByIdLocked(
+                windowId);
+        assertEquals(toString(layoutParams.accessibilityTitle), toString(a11yWindow.getTitle()));
+    }
+
+    @Test
+    public void sendAccessibilityEventOnWindowRemoval() {
+        final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
+
+        // Removing index 0 because it's not focused, and avoids unnecessary layer change.
+        final int windowId =
+                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
+        infos.remove(0);
+        for (WindowInfo info : infos) {
+            // Adjust layer number because it should start from 0.
+            info.layer--;
+        }
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(1))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(windowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_REMOVED)));
+    }
+
+    @Test
+    public void sendAccessibilityEventOnWindowAddition() throws RemoteException {
+        final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
+
+        for (WindowInfo info : infos) {
+            // Adjust layer number because new window will have 0 so that layer number in
+            // A11yWindowInfo in window won't be changed.
+            info.layer++;
+        }
+
+        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, USER_SYSTEM_ID);
+        addWindowInfo(infos, token, 0);
+        final int windowId =
+                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, infos.size() - 1);
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(1))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(windowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ADDED)));
+    }
+
+    @Test
+    public void sendAccessibilityEventOnWindowChange() {
+        final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
+        infos.get(0).title = "new title";
+        final int windowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(1))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(windowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_TITLE)));
+    }
+
+    private void registerLeashedTokenAndWindowId() {
+        mA11yWindowManager.registerIdLocked(mMockHostToken, HOST_WINDOW_ID);
+        mA11yWindowManager.registerIdLocked(mMockEmbeddedToken, EMBEDDED_WINDOW_ID);
+    }
+
+    private void startTrackingPerDisplay(int displayId) throws RemoteException {
+        ArrayList<WindowInfo> windowInfosForDisplay = new ArrayList<>();
+        // Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy
+        // mock window token into mA11yWindowTokens. Also, preparing WindowInfo mWindowInfos
+        // for the test.
+        int layer = 0;
+        for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) {
+            final IWindow token = addAccessibilityInteractionConnection(displayId,
+                    true, USER_SYSTEM_ID);
+            addWindowInfo(windowInfosForDisplay, token, layer++);
+
+        }
+        for (int i = 0; i < NUM_APP_WINDOWS; i++) {
+            final IWindow token = addAccessibilityInteractionConnection(displayId,
+                    false, USER_SYSTEM_ID);
+            addWindowInfo(windowInfosForDisplay, token, layer++);
+        }
+        // Sets up current focused window of display.
+        // Each display has its own current focused window if config_perDisplayFocusEnabled is true.
+        // Otherwise only default display needs to current focused window.
+        if (mSupportPerDisplayFocus || displayId == Display.DEFAULT_DISPLAY) {
+            windowInfosForDisplay.get(DEFAULT_FOCUSED_INDEX).focused = true;
+        }
+        // Turns on windows tracking, and update window info.
+        mA11yWindowManager.startTrackingWindows(displayId, false);
+        // Puts window lists into array.
+        mWindowInfos.put(displayId, windowInfosForDisplay);
+        // Sets the default display is the top focused display and
+        // its current focused window is the top focused window.
+        if (displayId == Display.DEFAULT_DISPLAY) {
+            setTopFocusedWindowAndDisplay(displayId, DEFAULT_FOCUSED_INDEX);
+        }
+        // Invokes callback for sending window lists to A11y framework.
+        onWindowsForAccessibilityChanged(displayId, FORCE_SEND);
+
+        assertEquals(mA11yWindowManager.getWindowListLocked(displayId).size(),
+                windowInfosForDisplay.size());
+    }
+
+    private WindowsForAccessibilityCallback getWindowsForAccessibilityCallbacks(int displayId) {
+        ArgumentCaptor<WindowsForAccessibilityCallback> windowsForAccessibilityCallbacksCaptor =
+                ArgumentCaptor.forClass(
+                        WindowsForAccessibilityCallback.class);
+        verify(mMockWindowManagerInternal)
+                .setWindowsForAccessibilityCallback(eq(displayId),
+                        windowsForAccessibilityCallbacksCaptor.capture());
+        return windowsForAccessibilityCallbacksCaptor.getValue();
+    }
+
+    private IWindow addAccessibilityInteractionConnection(int displayId, boolean bGlobal,
+            int userId) throws RemoteException {
+        final IWindow mockWindowToken = Mockito.mock(IWindow.class);
+        final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock(
+                IAccessibilityInteractionConnection.class);
+        final IBinder mockConnectionBinder = Mockito.mock(IBinder.class);
+        final IBinder mockWindowBinder = Mockito.mock(IBinder.class);
+        final IBinder mockLeashToken = Mockito.mock(IBinder.class);
+        when(mockA11yConnection.asBinder()).thenReturn(mockConnectionBinder);
+        when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder);
+        when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(userId))
+                .thenReturn(bGlobal);
+        when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowBinder))
+                .thenReturn(displayId);
+
+        int windowId = mA11yWindowManager.addAccessibilityInteractionConnection(
+                mockWindowToken, mockLeashToken, mockA11yConnection, PACKAGE_NAME, userId);
+        mA11yWindowTokens.put(windowId, mockWindowToken);
+        return mockWindowToken;
+    }
+
+    private int addAccessibilityInteractionConnection(int displayId, boolean bGlobal,
+            IBinder leashToken, int userId) throws RemoteException {
+        final IWindow mockWindowToken = Mockito.mock(IWindow.class);
+        final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock(
+                IAccessibilityInteractionConnection.class);
+        final IBinder mockConnectionBinder = Mockito.mock(IBinder.class);
+        final IBinder mockWindowBinder = Mockito.mock(IBinder.class);
+        when(mockA11yConnection.asBinder()).thenReturn(mockConnectionBinder);
+        when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder);
+        when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(userId))
+                .thenReturn(bGlobal);
+        when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowBinder))
+                .thenReturn(displayId);
+
+        int windowId = mA11yWindowManager.addAccessibilityInteractionConnection(
+                mockWindowToken, leashToken, mockA11yConnection, PACKAGE_NAME, userId);
+        mA11yWindowTokens.put(windowId, mockWindowToken);
+        return windowId;
+    }
+
+    private void addWindowInfo(ArrayList<WindowInfo> windowInfos, IWindow windowToken, int layer) {
+        final WindowInfo windowInfo = WindowInfo.obtain();
+        windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
+        windowInfo.token = windowToken.asBinder();
+        windowInfo.layer = layer;
+        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+        windowInfos.add(windowInfo);
+    }
+
+    private int getWindowIdFromWindowInfosForDisplay(int displayId, int index) {
+        final IBinder windowToken = mWindowInfos.get(displayId).get(index).token;
+        return mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, windowToken);
+    }
+
+    private void setTopFocusedWindowAndDisplay(int displayId, int index) {
+        // Sets the top focus window.
+        mTopFocusedWindowToken = mWindowInfos.get(displayId).get(index).token;
+        // Sets the top focused display.
+        mTopFocusedDisplayId = displayId;
+    }
+
+    private void onWindowsForAccessibilityChanged(int displayId, boolean forceSend) {
+        WindowsForAccessibilityCallback callbacks = mCallbackOfWindows.get(displayId);
+        if (callbacks == null) {
+            callbacks = getWindowsForAccessibilityCallbacks(displayId);
+            mCallbackOfWindows.put(displayId, callbacks);
+        }
+        callbacks.onWindowsForAccessibilityChanged(forceSend, mTopFocusedDisplayId,
+                mTopFocusedWindowToken, mWindowInfos.get(displayId));
+    }
+
+    private void changeFocusedWindowOnDisplayPerDisplayFocusConfig(
+            int changeFocusedDisplayId, int newFocusedWindowIndex, int oldTopFocusedDisplayId,
+            int oldFocusedWindowIndex) {
+        if (mSupportPerDisplayFocus) {
+            // Gets the old focused window of display which wants to change focused window.
+            WindowInfo focusedWindowInfo =
+                    mWindowInfos.get(changeFocusedDisplayId).get(oldFocusedWindowIndex);
+            // Resets the focus of old focused window.
+            focusedWindowInfo.focused = false;
+            // Gets the new window of display which wants to change focused window.
+            focusedWindowInfo =
+                    mWindowInfos.get(changeFocusedDisplayId).get(newFocusedWindowIndex);
+            // Sets the focus of new focused window.
+            focusedWindowInfo.focused = true;
+        } else {
+            // Gets the window of display which wants to change focused window.
+            WindowInfo focusedWindowInfo =
+                    mWindowInfos.get(changeFocusedDisplayId).get(newFocusedWindowIndex);
+            // Sets the focus of new focused window.
+            focusedWindowInfo.focused = true;
+            // Gets the old focused window of old top focused display.
+            focusedWindowInfo =
+                    mWindowInfos.get(oldTopFocusedDisplayId).get(oldFocusedWindowIndex);
+            // Resets the focus of old focused window.
+            focusedWindowInfo.focused = false;
+            // Changes the top focused display and window.
+            setTopFocusedWindowAndDisplay(changeFocusedDisplayId, newFocusedWindowIndex);
+        }
+    }
+
+    @Nullable
+    private static String toString(@Nullable CharSequence cs) {
+        return cs == null ? null : cs.toString();
+    }
+
+    static class DisplayIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
+        private final int mDisplayId;
+
+        DisplayIdMatcher(int displayId) {
+            super();
+            mDisplayId = displayId;
+        }
+
+        static DisplayIdMatcher displayId(int displayId) {
+            return new DisplayIdMatcher(displayId);
+        }
+
+        @Override
+        protected boolean matchesSafely(AccessibilityEvent event) {
+            return event.getDisplayId() == mDisplayId;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("Matching to displayId " + mDisplayId);
+        }
+    }
+
+    static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
+        private int mWindowId;
+
+        WindowIdMatcher(int windowId) {
+            super();
+            mWindowId = windowId;
+        }
+
+        static WindowIdMatcher a11yWindowId(int windowId) {
+            return new WindowIdMatcher(windowId);
+        }
+
+        @Override
+        protected boolean matchesSafely(AccessibilityEvent event) {
+            return event.getWindowId() == mWindowId;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("Matching to windowId " + mWindowId);
+        }
+    }
+
+    static class WindowChangesMatcher extends TypeSafeMatcher<AccessibilityEvent> {
+        private int mWindowChanges;
+
+        WindowChangesMatcher(int windowChanges) {
+            super();
+            mWindowChanges = windowChanges;
+        }
+
+        static WindowChangesMatcher a11yWindowChanges(int windowChanges) {
+            return new WindowChangesMatcher(windowChanges);
+        }
+
+        @Override
+        protected boolean matchesSafely(AccessibilityEvent event) {
+            return event.getWindowChanges() == mWindowChanges;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("Matching to window changes " + mWindowChanges);
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/BrailleDisplayConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/BrailleDisplayConnectionTest.java
index aec3f45..344e2c2 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/BrailleDisplayConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/BrailleDisplayConnectionTest.java
@@ -103,7 +103,7 @@
                 }
 
                 BrailleDisplayConnection.BrailleDisplayScanner scanner =
-                        mBrailleDisplayConnection.getDefaultNativeScanner(mNativeInterface);
+                        BrailleDisplayConnection.getDefaultNativeScanner(mNativeInterface);
 
                 assertThat(scanner.getHidrawNodePaths(testDir.toPath()))
                         .containsExactly(hidrawNode0, hidrawNode1);
@@ -123,7 +123,7 @@
                     descriptor);
 
             BrailleDisplayConnection.BrailleDisplayScanner scanner =
-                    mBrailleDisplayConnection.getDefaultNativeScanner(mNativeInterface);
+                    BrailleDisplayConnection.getDefaultNativeScanner(mNativeInterface);
 
             assertThat(scanner.getDeviceReportDescriptor(NULL_PATH)).isEqualTo(descriptor);
         }
@@ -133,7 +133,7 @@
             when(mNativeInterface.getHidrawDescSize(anyInt())).thenReturn(0);
 
             BrailleDisplayConnection.BrailleDisplayScanner scanner =
-                    mBrailleDisplayConnection.getDefaultNativeScanner(mNativeInterface);
+                    BrailleDisplayConnection.getDefaultNativeScanner(mNativeInterface);
 
             assertThat(scanner.getDeviceReportDescriptor(NULL_PATH)).isNull();
         }
@@ -144,7 +144,7 @@
             when(mNativeInterface.getHidrawUniq(anyInt())).thenReturn(macAddress);
 
             BrailleDisplayConnection.BrailleDisplayScanner scanner =
-                    mBrailleDisplayConnection.getDefaultNativeScanner(mNativeInterface);
+                    BrailleDisplayConnection.getDefaultNativeScanner(mNativeInterface);
 
             assertThat(scanner.getUniqueId(NULL_PATH)).isEqualTo(macAddress);
         }
@@ -155,7 +155,7 @@
                     .thenReturn(BrailleDisplayConnection.BUS_USB);
 
             BrailleDisplayConnection.BrailleDisplayScanner scanner =
-                    mBrailleDisplayConnection.getDefaultNativeScanner(mNativeInterface);
+                    BrailleDisplayConnection.getDefaultNativeScanner(mNativeInterface);
 
             assertThat(scanner.getDeviceBusType(NULL_PATH))
                     .isEqualTo(BrailleDisplayConnection.BUS_USB);
@@ -167,7 +167,7 @@
                     .thenReturn(BrailleDisplayConnection.BUS_BLUETOOTH);
 
             BrailleDisplayConnection.BrailleDisplayScanner scanner =
-                    mBrailleDisplayConnection.getDefaultNativeScanner(mNativeInterface);
+                    BrailleDisplayConnection.getDefaultNativeScanner(mNativeInterface);
 
             assertThat(scanner.getDeviceBusType(NULL_PATH))
                     .isEqualTo(BrailleDisplayConnection.BUS_BLUETOOTH);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java
index 009bfb7..87fe6cf 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java
@@ -813,6 +813,18 @@
                 anyBoolean());
     }
 
+    @Test
+    public void onFullscreenMagnificationActivationChanged_hasConnection_notifyActivatedState()
+            throws RemoteException {
+        mMagnificationConnectionManager.setConnection(mMockConnection.getConnection());
+
+        mMagnificationConnectionManager
+                .onFullscreenMagnificationActivationChanged(TEST_DISPLAY, /* activated= */ true);
+
+        verify(mMockConnection.getConnection())
+                .onFullscreenMagnificationActivationChanged(eq(TEST_DISPLAY), eq(true));
+    }
+
     private MotionEvent generatePointersDownEvent(PointF[] pointersLocation) {
         final int len = pointersLocation.length;
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionWrapperTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionWrapperTest.java
index 07f3036..2120b2e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionWrapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionWrapperTest.java
@@ -131,6 +131,14 @@
     }
 
     @Test
+    public void onFullscreenMagnificationActivationChanged() throws RemoteException {
+        mConnectionWrapper
+                .onFullscreenMagnificationActivationChanged(TEST_DISPLAY, /* activated= */ true);
+        verify(mConnection)
+                .onFullscreenMagnificationActivationChanged(eq(TEST_DISPLAY), eq(true));
+    }
+
+    @Test
     public void setMirrorWindowCallback() throws RemoteException {
         mConnectionWrapper.setConnectionCallback(mCallback);
         verify(mConnection).setConnectionCallback(mCallback);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index a0c4b5e..1a51c45 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -53,6 +53,10 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.provider.Settings;
 import android.test.mock.MockContentResolver;
 import android.testing.DexmakerShareClassLoaderRule;
@@ -73,6 +77,7 @@
 import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.accessibility.test.MessageCapturingHandler;
 import com.android.server.wm.WindowManagerInternal;
+import com.android.window.flags.Flags;
 
 import org.junit.After;
 import org.junit.Before;
@@ -91,6 +96,9 @@
 @RunWith(AndroidJUnit4.class)
 public class MagnificationControllerTest {
 
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
     private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
     private static final int TEST_SERVICE_ID = 1;
     private static final Region INITIAL_SCREEN_MAGNIFICATION_REGION =
@@ -1263,6 +1271,27 @@
         verify(mService).changeMagnificationMode(TEST_DISPLAY, MODE_WINDOW);
     }
 
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_MAGNIFICATION_ALWAYS_DRAW_FULLSCREEN_BORDER)
+    public void onFullscreenMagnificationActivationState_systemUiBorderFlagOn_notifyConnection() {
+        mMagnificationController.onFullScreenMagnificationActivationState(
+                TEST_DISPLAY, /* activated= */ true);
+
+        verify(mMagnificationConnectionManager)
+                .onFullscreenMagnificationActivationChanged(TEST_DISPLAY, /* activated= */ true);
+    }
+
+    @Test
+    @RequiresFlagsDisabled(Flags.FLAG_MAGNIFICATION_ALWAYS_DRAW_FULLSCREEN_BORDER)
+    public void
+            onFullscreenMagnificationActivationState_systemUiBorderFlagOff_neverNotifyConnection() {
+        mMagnificationController.onFullScreenMagnificationActivationState(
+                TEST_DISPLAY, /* activated= */ true);
+
+        verify(mMagnificationConnectionManager, never())
+                .onFullscreenMagnificationActivationChanged(TEST_DISPLAY, /* activated= */ true);
+    }
+
     private void setMagnificationEnabled(int mode) throws RemoteException {
         setMagnificationEnabled(mode, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
     }
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index caa2e36..e0a99b0 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -70,9 +70,10 @@
 import android.os.UserManager;
 import android.test.AndroidTestCase;
 import android.test.mock.MockContext;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.server.LocalServices;
 
 import org.mockito.ArgumentCaptor;
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
index 29a920a..61ac74c 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
@@ -21,7 +21,6 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -31,17 +30,16 @@
 import android.database.Cursor;
 import android.database.sqlite.SQLiteStatement;
 import android.os.Build;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Pair;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
diff --git a/services/tests/servicestests/src/com/android/server/adaptiveauth/AdaptiveAuthServiceTest.java b/services/tests/servicestests/src/com/android/server/adaptiveauth/AdaptiveAuthServiceTest.java
index 08a6529..1acb8ac 100644
--- a/services/tests/servicestests/src/com/android/server/adaptiveauth/AdaptiveAuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/adaptiveauth/AdaptiveAuthServiceTest.java
@@ -24,6 +24,7 @@
 import static com.android.server.adaptiveauth.AdaptiveAuthService.MAX_ALLOWED_FAILED_AUTH_ATTEMPTS;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -32,9 +33,11 @@
 
 import android.app.KeyguardManager;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.hardware.biometrics.AuthenticationStateListener;
 import android.hardware.biometrics.BiometricManager;
 import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
 import android.platform.test.flag.junit.SetFlagsRule;
 
 import androidx.test.InstrumentationRegistry;
@@ -62,6 +65,7 @@
 /**
  * atest FrameworksServicesTests:AdaptiveAuthServiceTest
  */
+@Presubmit
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class AdaptiveAuthServiceTest {
@@ -103,6 +107,10 @@
         mSetFlagsRule.enableFlags(FLAG_REPORT_BIOMETRIC_AUTH_ATTEMPTS);
 
         mContext = spy(ApplicationProvider.getApplicationContext());
+
+        assumeTrue("Adaptive auth is disabled on device",
+                !mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
+
         when(mContext.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager);
         when(mContext.getSystemService(KeyguardManager.class)).thenReturn(mKeyguardManager);
 
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
index 99eb047..0bf419e 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
@@ -52,7 +52,6 @@
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.server.wm.settings.SettingsSession;
-import android.test.suitebuilder.annotation.LargeTest;
 import android.text.TextUtils;
 import android.util.KeyValueListParser;
 import android.util.Log;
@@ -60,6 +59,7 @@
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.FlakyTest;
+import androidx.test.filters.LargeTest;
 import androidx.test.uiautomator.UiDevice;
 
 import org.junit.Before;
diff --git a/services/tests/servicestests/src/com/android/server/am/ServiceRestarterTest.java b/services/tests/servicestests/src/com/android/server/am/ServiceRestarterTest.java
index 4b359eb..cfcb3dd 100644
--- a/services/tests/servicestests/src/com/android/server/am/ServiceRestarterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ServiceRestarterTest.java
@@ -38,10 +38,10 @@
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.server.wm.settings.SettingsSession;
-import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.compatibility.common.util.SystemUtil;
diff --git a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
index 9acc4bd..8a7815e 100644
--- a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
@@ -47,11 +47,12 @@
 import android.os.Handler;
 import android.os.UserHandle;
 import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AtomicFile;
 import android.util.Xml;
 import android.widget.RemoteViews;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.servicestests.R;
 import com.android.internal.appwidget.IAppWidgetHost;
 import com.android.modules.utils.TypedXmlPullParser;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClientTest.java
index 5b81277..c12f13e 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClientTest.java
@@ -25,7 +25,8 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.server.biometrics.log.BiometricContext;
 import com.android.server.biometrics.log.BiometricLogger;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClientTest.java
index 9d0c84e..5d4b04f 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceGetFeatureClientTest.java
@@ -28,9 +28,9 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.TestableContext;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.server.biometrics.log.BiometricContext;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClientTest.java
index 1b4c017..a1e43fb 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClientTest.java
@@ -31,9 +31,9 @@
 import android.hardware.face.Face;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
-import android.test.suitebuilder.annotation.SmallTest;
 
 import androidx.annotation.NonNull;
+import androidx.test.filters.SmallTest;
 
 import com.android.server.biometrics.log.BiometricContext;
 import com.android.server.biometrics.log.BiometricLogger;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClientTest.java
index 8d74fd1..9845b58 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClientTest.java
@@ -31,7 +31,8 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.server.biometrics.log.BiometricContext;
 import com.android.server.biometrics.log.BiometricLogger;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClientTest.java
index dbbd69b..d6bc73e 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClientTest.java
@@ -28,7 +28,8 @@
 import android.hardware.biometrics.face.ISession;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.server.biometrics.log.BiometricContext;
 import com.android.server.biometrics.log.BiometricLogger;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceRevokeChallengeClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceRevokeChallengeClientTest.java
index fb5502a..e8cb5ad 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceRevokeChallengeClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceRevokeChallengeClientTest.java
@@ -25,7 +25,8 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.server.biometrics.log.BiometricContext;
 import com.android.server.biometrics.log.BiometricLogger;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClientTest.java
index eb8cc9c..b60c845 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceSetFeatureClientTest.java
@@ -27,9 +27,9 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.TestableContext;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.server.biometrics.log.BiometricContext;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSessionAdapterTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSessionAdapterTest.java
index b9a4fb4..b5d73d2 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSessionAdapterTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSessionAdapterTest.java
@@ -16,8 +16,8 @@
 
 package com.android.server.biometrics.sensors.face.hidl;
 
-import static com.android.server.biometrics.sensors.face.hidl.HidlToAidlSessionAdapter.ENROLL_TIMEOUT_SEC;
 import static com.android.server.biometrics.sensors.face.hidl.FaceGenerateChallengeClient.CHALLENGE_TIMEOUT_SEC;
+import static com.android.server.biometrics.sensors.face.hidl.HidlToAidlSessionAdapter.ENROLL_TIMEOUT_SEC;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -45,9 +45,9 @@
 import android.hardware.keymaster.Timestamp;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.TestableContext;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.server.biometrics.HardwareAuthTokenUtils;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClientTest.java
index 8409619..72b44d4 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClientTest.java
@@ -25,7 +25,8 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.server.biometrics.log.BiometricContext;
 import com.android.server.biometrics.log.BiometricLogger;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalEnumerateClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalEnumerateClientTest.java
index 723f916..b5df836 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalEnumerateClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalEnumerateClientTest.java
@@ -31,7 +31,8 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.server.biometrics.log.BiometricContext;
 import com.android.server.biometrics.log.BiometricLogger;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSessionAdapterTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSessionAdapterTest.java
index d723e87..cdf1266 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSessionAdapterTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSessionAdapterTest.java
@@ -28,7 +28,8 @@
 import android.hardware.keymaster.Timestamp;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.server.biometrics.sensors.fingerprint.aidl.AidlResponseHandler;
 
diff --git a/services/tests/servicestests/src/com/android/server/companion/utils/PackageUtilsTest.java b/services/tests/servicestests/src/com/android/server/companion/utils/PackageUtilsTest.java
index 01159b1..bcb4877 100644
--- a/services/tests/servicestests/src/com/android/server/companion/utils/PackageUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/utils/PackageUtilsTest.java
@@ -32,7 +32,6 @@
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
-import com.android.server.companion.PackageUtils;
 import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java b/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
index 0344663..28eee66 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
@@ -36,9 +36,9 @@
 import android.os.Bundle;
 import android.os.UserManager;
 import android.provider.ContactsContract;
-import android.test.suitebuilder.annotation.SmallTest;
 
 import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
index a694d5e..95f893b 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
@@ -21,7 +21,8 @@
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 /**
  * Test for SyncOperation.
diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionConsentManagerTest.java b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionConsentManagerTest.java
index 5fe60d7..b012aaa 100644
--- a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionConsentManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionConsentManagerTest.java
@@ -16,18 +16,26 @@
 
 package com.android.server.contentprotection;
 
+import static android.app.admin.DevicePolicyManager.CONTENT_PROTECTION_DISABLED;
+import static android.app.admin.DevicePolicyManager.CONTENT_PROTECTION_ENABLED;
+import static android.app.admin.DevicePolicyManager.CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY;
+import static android.view.contentprotection.flags.Flags.FLAG_MANAGE_DEVICE_POLICY_ENABLED;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
+import android.app.admin.DevicePolicyCache;
 import android.app.admin.DevicePolicyManagerInternal;
-import android.content.ContentResolver;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.UserHandle;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 import android.testing.TestableContentResolver;
 import android.testing.TestableContext;
@@ -36,6 +44,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.server.LocalServices;
+
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -78,29 +89,23 @@
     public final TestableContext mTestableContext =
             new TestableContext(ApplicationProvider.getApplicationContext());
 
+    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     private final TestableContentResolver mTestableContentResolver =
             mTestableContext.getContentResolver();
 
-    @Mock private ContentResolver mMockContentResolver;
-
     @Mock private DevicePolicyManagerInternal mMockDevicePolicyManagerInternal;
 
-    @Test
-    public void constructor_registersContentObserver() {
-        ContentProtectionConsentManager manager =
-                createContentProtectionConsentManager(mMockContentResolver);
+    @Mock private DevicePolicyCache mMockDevicePolicyCache;
 
-        assertThat(manager.mContentObserver).isNotNull();
-        verify(mMockContentResolver)
-                .registerContentObserver(
-                        URI_PACKAGE_VERIFIER_USER_CONSENT,
-                        /* notifyForDescendants= */ false,
-                        manager.mContentObserver,
-                        UserHandle.USER_ALL);
+    @Before
+    public void setup() {
+        setupLocalService(DevicePolicyManagerInternal.class, mMockDevicePolicyManagerInternal);
     }
 
     @Test
-    public void isConsentGranted_packageVerifierNotGranted() {
+    public void isConsentGranted_policyFlagDisabled_packageVerifierNotGranted() {
+        mSetFlagsRule.disableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
         ContentProtectionConsentManager manager =
                 createContentProtectionConsentManager(VALUE_FALSE, VALUE_TRUE);
 
@@ -108,10 +113,25 @@
 
         assertThat(actual).isFalse();
         verifyZeroInteractions(mMockDevicePolicyManagerInternal);
+        verifyZeroInteractions(mMockDevicePolicyCache);
     }
 
     @Test
-    public void isConsentGranted_contentProtectionNotGranted() {
+    public void isConsentGranted_policyFlagEnabled_packageVerifierNotGranted() {
+        mSetFlagsRule.enableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
+        ContentProtectionConsentManager manager =
+                createContentProtectionConsentManager(VALUE_FALSE, VALUE_TRUE);
+
+        boolean actual = manager.isConsentGranted(TEST_USER_ID);
+
+        assertThat(actual).isFalse();
+        verifyZeroInteractions(mMockDevicePolicyManagerInternal);
+        verifyZeroInteractions(mMockDevicePolicyCache);
+    }
+
+    @Test
+    public void isConsentGranted_policyFlagDisabled_contentProtectionNotGranted() {
+        mSetFlagsRule.disableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
         ContentProtectionConsentManager manager =
                 createContentProtectionConsentManager(VALUE_TRUE, VALUE_FALSE);
 
@@ -119,10 +139,12 @@
 
         assertThat(actual).isFalse();
         verifyZeroInteractions(mMockDevicePolicyManagerInternal);
+        verifyZeroInteractions(mMockDevicePolicyCache);
     }
 
     @Test
-    public void isConsentGranted_packageVerifierGranted_userNotManaged() {
+    public void isConsentGranted_policyFlagDisabled_packageVerifierGranted_userNotManaged() {
+        mSetFlagsRule.disableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
         ContentProtectionConsentManager manager =
                 createContentProtectionConsentManager(VALUE_TRUE, VALUE_TRUE);
 
@@ -130,10 +152,12 @@
 
         assertThat(actual).isTrue();
         verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
+        verifyZeroInteractions(mMockDevicePolicyCache);
     }
 
     @Test
-    public void isConsentGranted_packageVerifierGranted_userManaged() {
+    public void isConsentGranted_policyFlagDisabled_packageVerifierGranted_userManaged() {
+        mSetFlagsRule.disableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
         when(mMockDevicePolicyManagerInternal.isUserOrganizationManaged(TEST_USER_ID))
                 .thenReturn(true);
         ContentProtectionConsentManager manager =
@@ -142,21 +166,110 @@
         boolean actual = manager.isConsentGranted(TEST_USER_ID);
 
         assertThat(actual).isFalse();
+        verifyZeroInteractions(mMockDevicePolicyCache);
     }
 
     @Test
-    public void isConsentGranted_packageVerifierDefault() {
+    public void isConsentGranted_policyFlagEnabled_packageVerifierGranted_userNotManaged_contentProtectionNotGranted() {
+        mSetFlagsRule.enableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
         ContentProtectionConsentManager manager =
-                createContentProtectionConsentManager(VALUE_DEFAULT, VALUE_TRUE);
+                createContentProtectionConsentManager(VALUE_TRUE, VALUE_FALSE);
 
         boolean actual = manager.isConsentGranted(TEST_USER_ID);
 
         assertThat(actual).isFalse();
-        verifyZeroInteractions(mMockDevicePolicyManagerInternal);
+        verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
+        verifyZeroInteractions(mMockDevicePolicyCache);
     }
 
     @Test
-    public void isConsentGranted_contentProtectionDefault() {
+    public void isConsentGranted_policyFlagEnabled_packageVerifierGranted_userNotManaged_contentProtectionGranted() {
+        mSetFlagsRule.enableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
+        ContentProtectionConsentManager manager =
+                createContentProtectionConsentManager(VALUE_TRUE, VALUE_TRUE);
+
+        boolean actual = manager.isConsentGranted(TEST_USER_ID);
+
+        assertThat(actual).isTrue();
+        verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
+        verifyZeroInteractions(mMockDevicePolicyCache);
+    }
+
+    @Test
+    public void isConsentGranted_policyFlagEnabled_packageVerifierGranted_userManaged_policyDisabled() {
+        mSetFlagsRule.enableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
+        when(mMockDevicePolicyManagerInternal.isUserOrganizationManaged(TEST_USER_ID))
+                .thenReturn(true);
+        when(mMockDevicePolicyCache.getContentProtectionPolicy(TEST_USER_ID))
+                .thenReturn(CONTENT_PROTECTION_DISABLED);
+        ContentProtectionConsentManager manager =
+                createContentProtectionConsentManager(VALUE_TRUE, VALUE_TRUE);
+
+        boolean actual = manager.isConsentGranted(TEST_USER_ID);
+
+        assertThat(actual).isFalse();
+        verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
+        verify(mMockDevicePolicyCache).getContentProtectionPolicy(TEST_USER_ID);
+    }
+
+    @Test
+    public void isConsentGranted_policyFlagEnabled_packageVerifierGranted_userManaged_policyEnabled() {
+        mSetFlagsRule.enableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
+        when(mMockDevicePolicyManagerInternal.isUserOrganizationManaged(TEST_USER_ID))
+                .thenReturn(true);
+        when(mMockDevicePolicyCache.getContentProtectionPolicy(TEST_USER_ID))
+                .thenReturn(CONTENT_PROTECTION_ENABLED);
+        ContentProtectionConsentManager manager =
+                createContentProtectionConsentManager(VALUE_TRUE, VALUE_FALSE);
+
+        boolean actual = manager.isConsentGranted(TEST_USER_ID);
+
+        assertThat(actual).isTrue();
+        verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
+        verify(mMockDevicePolicyCache).getContentProtectionPolicy(TEST_USER_ID);
+    }
+
+    @Test
+    public void isConsentGranted_policyFlagEnabled_packageVerifierGranted_userManaged_policyNotControlled_contentProtectionGranted() {
+        mSetFlagsRule.enableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
+        when(mMockDevicePolicyManagerInternal.isUserOrganizationManaged(TEST_USER_ID))
+                .thenReturn(true);
+        when(mMockDevicePolicyCache.getContentProtectionPolicy(TEST_USER_ID))
+                .thenReturn(CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY);
+        ContentProtectionConsentManager manager =
+                createContentProtectionConsentManager(VALUE_TRUE, VALUE_TRUE);
+
+        boolean actual = manager.isConsentGranted(TEST_USER_ID);
+
+        assertThat(actual).isTrue();
+        verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
+        verify(mMockDevicePolicyCache).getContentProtectionPolicy(TEST_USER_ID);
+    }
+
+    @Test
+    public void isConsentGranted_policyFlagEnabled_packageVerifierGranted_userManaged_policyNotControlled_contentProtectionNotGranted() {
+        mSetFlagsRule.enableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
+        when(mMockDevicePolicyManagerInternal.isUserOrganizationManaged(TEST_USER_ID))
+                .thenReturn(true);
+        when(mMockDevicePolicyCache.getContentProtectionPolicy(TEST_USER_ID))
+                .thenReturn(CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY);
+        ContentProtectionConsentManager manager =
+                createContentProtectionConsentManager(VALUE_TRUE, VALUE_FALSE);
+
+        boolean actual = manager.isConsentGranted(TEST_USER_ID);
+
+        assertThat(actual).isFalse();
+        verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
+        verify(mMockDevicePolicyCache).getContentProtectionPolicy(TEST_USER_ID);
+    }
+
+    @Test
+    public void isConsentGranted_policyFlagEnabled_packageVerifierGranted_userManaged_policyNotControlled_contentProtectionDefault() {
+        mSetFlagsRule.enableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
+        when(mMockDevicePolicyManagerInternal.isUserOrganizationManaged(TEST_USER_ID))
+                .thenReturn(true);
+        when(mMockDevicePolicyCache.getContentProtectionPolicy(TEST_USER_ID))
+                .thenReturn(CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY);
         ContentProtectionConsentManager manager =
                 createContentProtectionConsentManager(VALUE_TRUE, VALUE_DEFAULT);
 
@@ -164,60 +277,150 @@
 
         assertThat(actual).isTrue();
         verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
+        verify(mMockDevicePolicyCache).getContentProtectionPolicy(TEST_USER_ID);
     }
 
     @Test
-    public void contentObserver_packageVerifier() {
+    public void isConsentGranted_policyFlagDisabled_packageVerifierDefault() {
+        mSetFlagsRule.disableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
         ContentProtectionConsentManager manager =
-                createContentProtectionConsentManager(VALUE_TRUE, VALUE_DEFAULT);
-        boolean firstActual = manager.isConsentGranted(TEST_USER_ID);
+                createContentProtectionConsentManager(VALUE_DEFAULT, VALUE_TRUE);
 
-        notifyContentObserver(
-                manager,
-                URI_PACKAGE_VERIFIER_USER_CONSENT,
-                KEY_PACKAGE_VERIFIER_USER_CONSENT,
-                VALUE_FALSE);
-        boolean secondActual = manager.isConsentGranted(TEST_USER_ID);
+        boolean actual = manager.isConsentGranted(TEST_USER_ID);
 
-        assertThat(firstActual).isTrue();
-        assertThat(secondActual).isFalse();
-        verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
+        assertThat(actual).isFalse();
+        verifyZeroInteractions(mMockDevicePolicyManagerInternal);
+        verifyZeroInteractions(mMockDevicePolicyCache);
     }
 
     @Test
-    public void contentObserver_contentProtection() {
+    public void isConsentGranted_policyFlagEnabled_packageVerifierDefault() {
+        mSetFlagsRule.enableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
         ContentProtectionConsentManager manager =
-                createContentProtectionConsentManager(VALUE_TRUE, VALUE_DEFAULT);
-        boolean firstActual = manager.isConsentGranted(TEST_USER_ID);
+                createContentProtectionConsentManager(VALUE_DEFAULT, VALUE_TRUE);
 
-        notifyContentObserver(
-                manager,
-                URI_CONTENT_PROTECTION_USER_CONSENT,
-                KEY_CONTENT_PROTECTION_USER_CONSENT,
-                VALUE_FALSE);
-        boolean secondActual = manager.isConsentGranted(TEST_USER_ID);
+        boolean actual = manager.isConsentGranted(TEST_USER_ID);
 
-        assertThat(firstActual).isTrue();
-        assertThat(secondActual).isFalse();
-        verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
+        assertThat(actual).isFalse();
+        verifyZeroInteractions(mMockDevicePolicyManagerInternal);
+        verifyZeroInteractions(mMockDevicePolicyCache);
     }
 
-    private void notifyContentObserver(
-            ContentProtectionConsentManager manager, Uri uri, String key, int value) {
+    @Test
+    public void isConsentGranted_policyFlagDisabled_contentProtectionDefault() {
+        mSetFlagsRule.disableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
+        ContentProtectionConsentManager manager =
+                createContentProtectionConsentManager(VALUE_TRUE, VALUE_DEFAULT);
+
+        boolean actual = manager.isConsentGranted(TEST_USER_ID);
+
+        assertThat(actual).isTrue();
+        verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
+        verifyZeroInteractions(mMockDevicePolicyCache);
+    }
+
+    @Test
+    public void contentObserver_policyFlagDisabled_packageVerifier() {
+        mSetFlagsRule.disableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
+        ContentProtectionConsentManager manager =
+                createContentProtectionConsentManager(VALUE_FALSE, VALUE_TRUE);
+
+        boolean firstActual = manager.isConsentGranted(TEST_USER_ID);
+        assertThat(firstActual).isFalse();
+        verify(mMockDevicePolicyManagerInternal, never()).isUserOrganizationManaged(anyInt());
+
+        putGlobalSettings(KEY_PACKAGE_VERIFIER_USER_CONSENT, VALUE_TRUE);
+        boolean secondActual = manager.isConsentGranted(TEST_USER_ID);
+        assertThat(secondActual).isFalse();
+        verify(mMockDevicePolicyManagerInternal, never()).isUserOrganizationManaged(anyInt());
+
+        notifyContentObserver(manager, URI_PACKAGE_VERIFIER_USER_CONSENT);
+        boolean thirdActual = manager.isConsentGranted(TEST_USER_ID);
+        assertThat(thirdActual).isTrue();
+        verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
+
+        verifyZeroInteractions(mMockDevicePolicyCache);
+    }
+
+    @Test
+    public void contentObserver_policyFlagEnabled_packageVerifier() {
+        mSetFlagsRule.enableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
+        ContentProtectionConsentManager manager =
+                createContentProtectionConsentManager(VALUE_FALSE, VALUE_TRUE);
+
+        boolean firstActual = manager.isConsentGranted(TEST_USER_ID);
+        assertThat(firstActual).isFalse();
+        verify(mMockDevicePolicyManagerInternal, never()).isUserOrganizationManaged(anyInt());
+
+        putGlobalSettings(KEY_PACKAGE_VERIFIER_USER_CONSENT, VALUE_TRUE);
+        boolean secondActual = manager.isConsentGranted(TEST_USER_ID);
+        assertThat(secondActual).isFalse();
+        verify(mMockDevicePolicyManagerInternal, never()).isUserOrganizationManaged(anyInt());
+
+        notifyContentObserver(manager, URI_PACKAGE_VERIFIER_USER_CONSENT);
+        boolean thirdActual = manager.isConsentGranted(TEST_USER_ID);
+        assertThat(thirdActual).isTrue();
+        verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
+
+        verifyZeroInteractions(mMockDevicePolicyCache);
+    }
+
+    @Test
+    public void contentObserver_policyFlagDisabled_contentProtection() {
+        mSetFlagsRule.disableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
+        ContentProtectionConsentManager manager =
+                createContentProtectionConsentManager(VALUE_TRUE, VALUE_FALSE);
+
+        boolean firstActual = manager.isConsentGranted(TEST_USER_ID);
+        assertThat(firstActual).isFalse();
+        verify(mMockDevicePolicyManagerInternal, never()).isUserOrganizationManaged(anyInt());
+
+        putGlobalSettings(KEY_CONTENT_PROTECTION_USER_CONSENT, VALUE_TRUE);
+        boolean secondActual = manager.isConsentGranted(TEST_USER_ID);
+        assertThat(secondActual).isFalse();
+        verify(mMockDevicePolicyManagerInternal, never()).isUserOrganizationManaged(anyInt());
+
+        notifyContentObserver(manager, URI_CONTENT_PROTECTION_USER_CONSENT);
+        boolean thirdActual = manager.isConsentGranted(TEST_USER_ID);
+        assertThat(thirdActual).isTrue();
+        verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
+
+        verifyZeroInteractions(mMockDevicePolicyCache);
+    }
+
+    @Test
+    public void contentObserver_policyFlagEnabled_contentProtection() {
+        mSetFlagsRule.enableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED);
+        ContentProtectionConsentManager manager =
+                createContentProtectionConsentManager(VALUE_TRUE, VALUE_FALSE);
+
+        boolean firstActual = manager.isConsentGranted(TEST_USER_ID);
+        assertThat(firstActual).isFalse();
+        verify(mMockDevicePolicyManagerInternal).isUserOrganizationManaged(TEST_USER_ID);
+
+        putGlobalSettings(KEY_CONTENT_PROTECTION_USER_CONSENT, VALUE_TRUE);
+        boolean secondActual = manager.isConsentGranted(TEST_USER_ID);
+        assertThat(secondActual).isFalse();
+        verify(mMockDevicePolicyManagerInternal, times(2)).isUserOrganizationManaged(TEST_USER_ID);
+
+        notifyContentObserver(manager, URI_CONTENT_PROTECTION_USER_CONSENT);
+        boolean thirdActual = manager.isConsentGranted(TEST_USER_ID);
+        assertThat(thirdActual).isTrue();
+        verify(mMockDevicePolicyManagerInternal, times(3)).isUserOrganizationManaged(TEST_USER_ID);
+
+        verifyZeroInteractions(mMockDevicePolicyCache);
+    }
+
+    private void putGlobalSettings(String key, int value) {
         Settings.Global.putInt(mTestableContentResolver, key, value);
+    }
+
+    private void notifyContentObserver(ContentProtectionConsentManager manager, Uri uri) {
         // Observer has to be called manually, mTestableContentResolver is not propagating
         manager.mContentObserver.onChange(/* selfChange= */ false, uri, TEST_USER_ID);
     }
 
     private ContentProtectionConsentManager createContentProtectionConsentManager(
-            ContentResolver contentResolver) {
-        return new ContentProtectionConsentManager(
-                new Handler(Looper.getMainLooper()),
-                contentResolver,
-                mMockDevicePolicyManagerInternal);
-    }
-
-    private ContentProtectionConsentManager createContentProtectionConsentManager(
             int valuePackageVerifierUserConsent, int valueContentProtectionUserConsent) {
         Settings.Global.putInt(
                 mTestableContentResolver,
@@ -227,6 +430,14 @@
                 mTestableContentResolver,
                 KEY_CONTENT_PROTECTION_USER_CONSENT,
                 valueContentProtectionUserConsent);
-        return createContentProtectionConsentManager(mTestableContentResolver);
+        return new ContentProtectionConsentManager(
+                new Handler(Looper.getMainLooper()),
+                mTestableContentResolver,
+                mMockDevicePolicyCache);
+    }
+
+    private <T> void setupLocalService(Class<T> clazz, T service) {
+        LocalServices.removeServiceForTest(clazz);
+        LocalServices.addService(clazz, service);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyConstantsTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyConstantsTest.java
index 9660d6b..5f60ad9 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyConstantsTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyConstantsTest.java
@@ -17,7 +17,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java
index d55f379..8a9538f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java
@@ -37,7 +37,8 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.test.TestLooper;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
index 375b52d..e81231a 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
@@ -25,8 +25,8 @@
 
 import android.content.ComponentName;
 import android.os.IpcDataCache;
-import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index a6e05dd..5520897 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -364,6 +364,30 @@
     }
 
     @Test
+    public void systemAudioControlOnPowerOn_singleActionStarted() throws Exception {
+        mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class);
+        mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn(
+                Constants.ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, true);
+        mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn(
+                Constants.ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, true);
+        assertThat(
+                mHdmiCecLocalDeviceAudioSystem.getActions(
+                        SystemAudioInitiationActionFromAvr.class))
+                .hasSize(1);
+    }
+
+    @Test
+    public void onSystemAudioControlFeatureSupportChanged_singleActionStarted() throws Exception {
+        mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class);
+        mHdmiCecLocalDeviceAudioSystem.onSystemAudioControlFeatureSupportChanged(true);
+        mHdmiCecLocalDeviceAudioSystem.onSystemAudioControlFeatureSupportChanged(true);
+        assertThat(
+                mHdmiCecLocalDeviceAudioSystem.getActions(
+                        SystemAudioInitiationActionFromAvr.class))
+                .hasSize(1);
+    }
+
+    @Test
     public void handleActiveSource_updateActiveSource() throws Exception {
         HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
         ActiveSource expectedActiveSource = new ActiveSource(ADDR_TV, 0x0000);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index e59b5ea..2ba3969 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -48,7 +48,6 @@
 import android.os.storage.IStorageManager;
 import android.os.storage.StorageManager;
 import android.provider.Settings;
-import android.security.KeyStore;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
@@ -102,7 +101,6 @@
     IActivityManager mActivityManager;
     DevicePolicyManager mDevicePolicyManager;
     DevicePolicyManagerInternal mDevicePolicyManagerInternal;
-    KeyStore mKeyStore;
     MockSyntheticPasswordManager mSpManager;
     IAuthSecret mAuthSecretService;
     WindowManagerInternal mMockWindowManager;
@@ -165,7 +163,6 @@
                 new LockSettingsServiceTestable.MockInjector(
                         mContext,
                         mStorage,
-                        mKeyStore,
                         mActivityManager,
                         setUpStorageManagerMock(),
                         mSpManager,
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index 296d2cb..f9077c4 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -30,7 +30,6 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.storage.IStorageManager;
-import android.security.KeyStore;
 import android.security.keystore.KeyPermanentlyInvalidatedException;
 import android.service.gatekeeper.IGateKeeperService;
 
@@ -41,6 +40,7 @@
 import com.android.server.pm.UserManagerInternal;
 
 import java.io.FileNotFoundException;
+import java.security.KeyStore;
 
 public class LockSettingsServiceTestable extends LockSettingsService {
     private Intent mSavedFrpNotificationIntent = null;
@@ -50,7 +50,6 @@
     public static class MockInjector extends LockSettingsService.Injector {
 
         private LockSettingsStorage mLockSettingsStorage;
-        private KeyStore mKeyStore;
         private IActivityManager mActivityManager;
         private IStorageManager mStorageManager;
         private SyntheticPasswordManager mSpManager;
@@ -62,14 +61,13 @@
         public boolean mIsHeadlessSystemUserMode = false;
         public boolean mIsMainUserPermanentAdmin = false;
 
-        public MockInjector(Context context, LockSettingsStorage storage, KeyStore keyStore,
-                IActivityManager activityManager,
-                IStorageManager storageManager, SyntheticPasswordManager spManager,
-                FakeGsiService gsiService, RecoverableKeyStoreManager recoverableKeyStoreManager,
+        public MockInjector(Context context, LockSettingsStorage storage,
+                IActivityManager activityManager, IStorageManager storageManager,
+                SyntheticPasswordManager spManager, FakeGsiService gsiService,
+                RecoverableKeyStoreManager recoverableKeyStoreManager,
                 UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache) {
             super(context);
             mLockSettingsStorage = storage;
-            mKeyStore = keyStore;
             mActivityManager = activityManager;
             mStorageManager = storageManager;
             mSpManager = spManager;
@@ -110,11 +108,6 @@
         }
 
         @Override
-        public KeyStore getKeyStore() {
-            return mKeyStore;
-        }
-
-        @Override
         public IStorageManager getStorageManager() {
             return mStorageManager;
         }
@@ -145,8 +138,7 @@
         }
 
         @Override
-        public UnifiedProfilePasswordCache getUnifiedProfilePasswordCache(
-                java.security.KeyStore ks) {
+        public UnifiedProfilePasswordCache getUnifiedProfilePasswordCache(KeyStore ks) {
             return mock(UnifiedProfilePasswordCache.class);
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
index d6d2b6d..07fb9fc 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
@@ -52,9 +52,9 @@
 import android.os.RemoteException;
 import android.os.test.FakePermissionEnforcer;
 import android.platform.test.annotations.Presubmit;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArrayMap;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.app.IBatteryStats;
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 5c6f3c9..1249707 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -149,6 +149,7 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkPolicy;
+import android.net.NetworkPolicyManager;
 import android.net.NetworkStateSnapshot;
 import android.net.NetworkTemplate;
 import android.net.TelephonyNetworkSpecifier;
@@ -176,7 +177,6 @@
 import android.telephony.SubscriptionPlan;
 import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -190,6 +190,7 @@
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.FlakyTest;
+import androidx.test.filters.MediumTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.util.test.BroadcastInterceptingContext;
@@ -1619,6 +1620,12 @@
         verify(mActivityManagerInternal).notifyNetworkPolicyRulesUpdated(UID_A, procStateSeq);
     }
 
+    private void callAndWaitOnUidGone(int uid) throws Exception {
+        // The disabled argument is used only for ephemeral apps and does not matter here.
+        mUidObserver.onUidGone(uid, false /* disabled */);
+        waitForUidEventHandlerIdle();
+    }
+
     private void callAndWaitOnUidStateChanged(int uid, int procState, long procStateSeq)
             throws Exception {
         callAndWaitOnUidStateChanged(uid, procState, procStateSeq,
@@ -2245,6 +2252,15 @@
         assertTrue(mService.isUidNetworkingBlocked(UID_A, false));
     }
 
+    private boolean isUidState(int uid, int procState, int procStateSeq, int capability) {
+        final NetworkPolicyManager.UidState uidState = mService.getUidStateForTest(uid);
+        if (uidState == null) {
+            return false;
+        }
+        return uidState.uid == uid && uidState.procStateSeq == procStateSeq
+                && uidState.procState == procState && uidState.capability == capability;
+    }
+
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
     public void testUidObserverFiltersProcStateChanges() throws Exception {
@@ -2363,6 +2379,70 @@
     }
 
     @Test
+    public void testUidStateChangeAfterUidGone() throws Exception {
+        final int testProcStateSeq = 51;
+        final int testProcState = PROCESS_STATE_IMPORTANT_FOREGROUND;
+
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // First callback for uid.
+            callOnUidStatechanged(UID_B, testProcState, testProcStateSeq, PROCESS_CAPABILITY_NONE);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        assertTrue(isUidState(UID_B, testProcState, testProcStateSeq, PROCESS_CAPABILITY_NONE));
+
+        callAndWaitOnUidGone(UID_B);
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Even though the procState is the same, the uid had exited - so this should be
+            // processed as a fresh callback.
+            callOnUidStatechanged(UID_B, testProcState, testProcStateSeq + 1,
+                    PROCESS_CAPABILITY_NONE);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        assertTrue(isUidState(UID_B, testProcState, testProcStateSeq + 1, PROCESS_CAPABILITY_NONE));
+    }
+
+    @Test
+    public void testObsoleteHandleUidGone() throws Exception {
+        callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_TOP, 51);
+        assertFalse(mService.isUidNetworkingBlocked(UID_A, false));
+
+        clearInvocations(mNetworkManager);
+
+        // In the service, handleUidGone is only called from mUidEventHandler. Then a call to it may
+        // be rendered obsolete by a newer uid change posted on the handler. The latest uid state
+        // change is always reflected in the current UidStateChangeCallbackInfo for the uid, so to
+        // simulate an obsolete call for test, we directly call handleUidGone and leave the state in
+        // UidStateChangeCallbackInfo set by the previous call to onUidStateChanged(TOP). This call
+        // should then do nothing.
+        mService.handleUidGone(UID_A);
+
+        verify(mNetworkManager, times(0)).setFirewallUidRule(anyInt(), anyInt(), anyInt());
+        assertFalse(mService.isUidNetworkingBlocked(UID_A, false));
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
+    public void testObsoleteHandleUidChanged() throws Exception {
+        callAndWaitOnUidGone(UID_A);
+        assertTrue(mService.isUidNetworkingBlocked(UID_A, false));
+
+        clearInvocations(mNetworkManager);
+
+        // In the service, handleUidChanged is only called from mUidEventHandler. Then a call to it
+        // may be rendered obsolete by an immediate uid-gone posted on the handler. The latest uid
+        // state change is always reflected in the current UidStateChangeCallbackInfo for the uid,
+        // so to simulate an obsolete call for test, we directly call handleUidChanged and leave the
+        // state in UidStateChangeCallbackInfo as null as it would get removed by the previous call
+        // to onUidGone(). This call should then do nothing.
+        mService.handleUidChanged(UID_A);
+
+        verify(mNetworkManager, times(0)).setFirewallUidRule(anyInt(), anyInt(), anyInt());
+        assertTrue(mService.isUidNetworkingBlocked(UID_A, false));
+    }
+
+    @Test
     public void testLowPowerStandbyAllowlist() throws Exception {
         // Chain background is also enabled but these procstates are important enough to be exempt.
         callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_TOP, 0);
diff --git a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
index ea84eb2..e0ef035 100644
--- a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
@@ -16,8 +16,6 @@
 
 package com.android.server.os;
 
-import android.app.admin.flags.Flags;
-
 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -27,15 +25,19 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.when;
 
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.flags.Flags;
 import android.app.role.RoleManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.BugreportManager.BugreportCallback;
+import android.os.BugreportParams;
 import android.os.IBinder;
 import android.os.IDumpstateListener;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.UserManager;
 import android.platform.test.annotations.RequiresFlagsDisabled;
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
@@ -75,6 +77,10 @@
 
     @Mock
     private PackageManager mPackageManager;
+    @Mock
+    private UserManager mMockUserManager;
+    @Mock
+    private DevicePolicyManager mMockDevicePolicyManager;
 
     private int mCallingUid = 1234;
     private String mCallingPackage  = "test.package";
@@ -91,10 +97,12 @@
         ArraySet<String> mAllowlistedPackages = new ArraySet<>();
         mAllowlistedPackages.add(mContext.getPackageName());
         mService = new BugreportManagerServiceImpl(
-                new BugreportManagerServiceImpl.Injector(mContext, mAllowlistedPackages,
-                        mMappingFile));
+                new TestInjector(mContext, mAllowlistedPackages, mMappingFile,
+                        mMockUserManager, mMockDevicePolicyManager));
         mBugreportFileManager = new BugreportManagerServiceImpl.BugreportFileManager(mMappingFile);
         when(mPackageManager.getPackageUidAsUser(anyString(), anyInt())).thenReturn(mCallingUid);
+        // The calling user is an admin user by default.
+        when(mMockUserManager.isUserAdmin(anyInt())).thenReturn(true);
     }
 
     @After
@@ -182,6 +190,36 @@
     }
 
     @Test
+    public void testStartBugreport_throwsForNonAdminUser() throws Exception {
+        when(mMockUserManager.isUserAdmin(anyInt())).thenReturn(false);
+
+        Exception thrown = assertThrows(IllegalArgumentException.class,
+                () -> mService.startBugreport(mCallingUid, mContext.getPackageName(),
+                        new FileDescriptor(), /* screenshotFd= */ null,
+                        BugreportParams.BUGREPORT_MODE_FULL,
+                        /* flags= */ 0, new Listener(new CountDownLatch(1)),
+                        /* isScreenshotRequested= */ false));
+
+        assertThat(thrown.getMessage()).contains("not an admin user");
+    }
+
+    @Test
+    public void testStartBugreport_throwsForNotAffiliatedUser() throws Exception {
+        when(mMockUserManager.isUserAdmin(anyInt())).thenReturn(false);
+        when(mMockDevicePolicyManager.getDeviceOwnerUserId()).thenReturn(-1);
+        when(mMockDevicePolicyManager.isAffiliatedUser(anyInt())).thenReturn(false);
+
+        Exception thrown = assertThrows(IllegalArgumentException.class,
+                () -> mService.startBugreport(mCallingUid, mContext.getPackageName(),
+                        new FileDescriptor(), /* screenshotFd= */ null,
+                        BugreportParams.BUGREPORT_MODE_REMOTE,
+                        /* flags= */ 0, new Listener(new CountDownLatch(1)),
+                        /* isScreenshotRequested= */ false));
+
+        assertThat(thrown.getMessage()).contains("not affiliated to the device owner");
+    }
+
+    @Test
     public void testRetrieveBugreportWithoutFilesForCaller() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
         Listener listener = new Listener(latch);
@@ -224,7 +262,8 @@
 
     private void clearAllowlist() {
         mService = new BugreportManagerServiceImpl(
-                new BugreportManagerServiceImpl.Injector(mContext, new ArraySet<>(), mMappingFile));
+                new TestInjector(mContext, new ArraySet<>(), mMappingFile,
+                        mMockUserManager, mMockDevicePolicyManager));
     }
 
     private static class Listener implements IDumpstateListener {
@@ -275,4 +314,27 @@
             complete(successful);
         }
     }
+
+    private static class TestInjector extends BugreportManagerServiceImpl.Injector {
+
+        private final UserManager mUserManager;
+        private final DevicePolicyManager mDevicePolicyManager;
+
+        TestInjector(Context context, ArraySet<String> allowlistedPackages, AtomicFile mappingFile,
+                UserManager um, DevicePolicyManager dpm) {
+            super(context, allowlistedPackages, mappingFile);
+            mUserManager = um;
+            mDevicePolicyManager = dpm;
+        }
+
+        @Override
+        public UserManager getUserManager() {
+            return mUserManager;
+        }
+
+        @Override
+        public DevicePolicyManager getDevicePolicyManager() {
+            return mDevicePolicyManager;
+        }
+    }
 }
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 44c464e..507b3fe 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -40,13 +40,13 @@
 import android.platform.test.annotations.Postsubmit;
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.provider.Settings;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.util.ArraySet;
 import android.util.Slog;
 
 import androidx.annotation.Nullable;
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
diff --git a/services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java b/services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java
index 0635cc4..669eedf 100644
--- a/services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java
@@ -32,13 +32,13 @@
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.test.TestLooper;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableContext;
 import android.testing.TestableResources;
 import android.view.Window;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 
 import com.android.internal.R;
 
diff --git a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
index ca0270d..db7822d 100644
--- a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
@@ -47,7 +47,8 @@
 import android.provider.Settings;
 import android.service.attention.AttentionService;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.server.wm.WindowManagerInternal;
 
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
index 6fffd75..fe9a0e2 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
@@ -29,10 +29,11 @@
 import android.provider.DeviceConfig;
 import android.provider.Settings.Global;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.util.ArrayMap;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+
 import com.android.frameworks.servicestests.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.power.batterysaver.BatterySaverPolicy.Policy;
diff --git a/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java b/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java
index 517f483..cb5371b 100644
--- a/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java
@@ -26,8 +26,8 @@
 import android.app.usage.UsageStatsManager;
 import android.content.res.Configuration;
 import android.os.PersistableBundle;
-import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.util.ArrayUtils;
diff --git a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
index cd29c80..f388528 100644
--- a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
+++ b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
@@ -31,11 +31,11 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.os.PersistableBundle;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AtomicFile;
 import android.util.LongSparseArray;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java b/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java
index c8bef45..44d1161 100644
--- a/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java
+++ b/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java
@@ -147,7 +147,7 @@
             final int n = 4;
             StackTraceElement[] stack = Thread.currentThread().getStackTrace();
             if (stack.length < n+1) return "test";
-            return stack[n].getMethodName();
+            return stack[n].getClassName() + "." + stack[n].getMethodName();
         }
     }
 
@@ -312,12 +312,17 @@
     }
 
     /**
-     * Verify the dump output.
+     * Verify the dump output.  This only applies when native timers are supported.
      */
     @Test
     public void testDumpOutput() throws Exception {
+        if (!AnrTimer.nativeTimersSupported()) return;
+
+        // The timers in this class are named "class.method".
+        final String timerName = "timer: com.android.server.utils.AnrTimerTest";
+
         String r1 = getDumpOutput();
-        assertThat(r1).doesNotContain("timer:");
+        assertThat(r1).doesNotContain(timerName);
 
         Helper helper = new Helper(2);
         TestArg t1 = new TestArg(1, 1);
@@ -331,14 +336,14 @@
             String r2 = getDumpOutput();
             // There are timers in the list if and only if the feature is enabled.
             if (mEnabled) {
-              assertThat(r2).contains("timer:");
+                assertThat(r2).contains(timerName);
             } else {
-              assertThat(r2).doesNotContain("timer:");
+                assertThat(r2).doesNotContain(timerName);
             }
         }
 
         String r3 = getDumpOutput();
-        assertThat(r3).doesNotContain("timer:");
+        assertThat(r3).doesNotContain(timerName);
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
index 2039f93..54d1138 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
@@ -96,6 +96,9 @@
             return;
         }
         PackageInfo packageInfo = userPackages.get(userId);
+        if (packageInfo == null) {
+            return;
+        }
         packageInfo.applicationInfo.enabled = enable;
         setPackageInfoForUser(userId, packageInfo);
     }
@@ -106,6 +109,9 @@
             return;
         }
         PackageInfo packageInfo = userPackages.get(userId);
+        if (packageInfo == null) {
+            return;
+        }
         packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
         packageInfo.applicationInfo.privateFlags &= (~ApplicationInfo.PRIVATE_FLAG_HIDDEN);
         setPackageInfoForUser(userId, packageInfo);
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index 53c172a..e181a51 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -31,7 +31,6 @@
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Base64;
 import android.webkit.UserPackage;
 import android.webkit.WebViewFactory;
@@ -39,6 +38,7 @@
 import android.webkit.WebViewProviderResponse;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
@@ -1551,7 +1551,7 @@
 
     @Test
     @RequiresFlagsEnabled("android.webkit.update_service_v2")
-    public void testDefaultWebViewPackageInstalling() {
+    public void testDefaultWebViewPackageInstallingDuringStartUp() {
         String testPackage = "testDefault";
         WebViewProviderInfo[] packages =
                 new WebViewProviderInfo[] {
@@ -1574,6 +1574,68 @@
                         Matchers.anyObject(), Mockito.eq(testPackage));
     }
 
+    @Test
+    @RequiresFlagsEnabled("android.webkit.update_service_v2")
+    public void testDefaultWebViewPackageInstallingAfterStartUp() {
+        String testPackage = "testDefault";
+        WebViewProviderInfo[] packages =
+                new WebViewProviderInfo[] {
+                    new WebViewProviderInfo(
+                            testPackage,
+                            "",
+                            true /* default available */,
+                            false /* fallback */,
+                            null)
+                };
+        checkCertainPackageUsedAfterWebViewBootPreparation(testPackage, packages);
+
+        // uninstall the default package.
+        mTestSystemImpl.setPackageInfo(
+                createPackageInfo(
+                        testPackage, true /* enabled */, true /* valid */, false /* installed */));
+        mWebViewUpdateServiceImpl.packageStateChanged(testPackage,
+                WebViewUpdateService.PACKAGE_REMOVED, 0);
+
+        // Check that we try to re-install the default package.
+        Mockito.verify(mTestSystemImpl)
+                .installExistingPackageForAllUsers(
+                        Matchers.anyObject(), Mockito.eq(testPackage));
+    }
+
+    /**
+     * Ensures that adding a new user for which the current WebView package is uninstalled triggers
+     * the repair logic.
+     */
+    @Test
+    @RequiresFlagsEnabled("android.webkit.update_service_v2")
+    public void testAddingNewUserWithDefaultdPackageNotInstalled() {
+        String testPackage = "testDefault";
+        WebViewProviderInfo[] packages =
+                new WebViewProviderInfo[] {
+                    new WebViewProviderInfo(
+                            testPackage,
+                            "",
+                            true /* default available */,
+                            false /* fallback */,
+                            null)
+                };
+        checkCertainPackageUsedAfterWebViewBootPreparation(testPackage, packages);
+
+        // Add new user with the default package not installed.
+        int newUser = 100;
+        mTestSystemImpl.addUser(newUser);
+        mTestSystemImpl.setPackageInfoForUser(newUser,
+                createPackageInfo(testPackage, true /* enabled */, true /* valid */,
+                        false /* installed */));
+
+        mWebViewUpdateServiceImpl.handleNewUser(newUser);
+
+        // Check that we try to re-install the default package for all users.
+        Mockito.verify(mTestSystemImpl)
+                .installExistingPackageForAllUsers(
+                        Matchers.anyObject(), Mockito.eq(testPackage));
+    }
+
     private void testDefaultPackageChosen(PackageInfo packageInfo) {
         WebViewProviderInfo[] packages =
                 new WebViewProviderInfo[] {
diff --git a/services/tests/servicestests/utils/com/android/server/testutils/StubTransaction.java b/services/tests/servicestests/utils/com/android/server/testutils/StubTransaction.java
index e27bb4c..b9ece93 100644
--- a/services/tests/servicestests/utils/com/android/server/testutils/StubTransaction.java
+++ b/services/tests/servicestests/utils/com/android/server/testutils/StubTransaction.java
@@ -40,12 +40,19 @@
 public class StubTransaction extends SurfaceControl.Transaction {
 
     private HashSet<Runnable> mWindowInfosReportedListeners = new HashSet<>();
+    private HashSet<SurfaceControl.TransactionCommittedListener> mTransactionCommittedListeners =
+            new HashSet<>();
 
     @Override
     public void apply() {
         for (Runnable listener : mWindowInfosReportedListeners) {
             listener.run();
         }
+        for (SurfaceControl.TransactionCommittedListener listener
+                : mTransactionCommittedListeners) {
+            listener.onTransactionCommitted();
+        }
+        mTransactionCommittedListeners.clear();
     }
 
     @Override
@@ -239,6 +246,9 @@
     @Override
     public SurfaceControl.Transaction addTransactionCommittedListener(Executor executor,
             SurfaceControl.TransactionCommittedListener listener) {
+        SurfaceControl.TransactionCommittedListener listenerInner =
+                () -> executor.execute(listener::onTransactionCommitted);
+        mTransactionCommittedListeners.add(listenerInner);
         return this;
     }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/AlertRateLimiterTest.java b/services/tests/uiservicestests/src/com/android/server/notification/AlertRateLimiterTest.java
index dc7f118..f229fd9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/AlertRateLimiterTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/AlertRateLimiterTest.java
@@ -20,8 +20,7 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
-import android.test.suitebuilder.annotation.SmallTest;
-
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
index 8bc027d..39ff9cc 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
@@ -33,8 +33,8 @@
 import android.os.UserManager;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.service.notification.StatusBarNotification;
-import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
index ce6939a9..2f5c96c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
@@ -35,8 +35,8 @@
 import android.media.session.MediaSession;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java
index 9dffed2..b5bc610 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java
@@ -48,8 +48,8 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 8622488..517dcb4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -74,12 +74,12 @@
 import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.IAccessibilityManager;
 import android.view.accessibility.IAccessibilityManagerClient;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.logging.InstanceIdSequence;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/DefaultDeviceEffectsApplierTest.java b/services/tests/uiservicestests/src/com/android/server/notification/DefaultDeviceEffectsApplierTest.java
index 3797dbb..bfbc81c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/DefaultDeviceEffectsApplierTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/DefaultDeviceEffectsApplierTest.java
@@ -29,9 +29,11 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
@@ -103,8 +105,10 @@
         mContext.addMockSystemService(ColorDisplayManager.class, mColorDisplayManager);
         mContext.addMockSystemService(UiModeManager.class, mUiModeManager);
         mContext.addMockSystemService(WallpaperManager.class, mWallpaperManager);
+        when(mWallpaperManager.isWallpaperSupported()).thenReturn(true);
 
         mApplier = new DefaultDeviceEffectsApplier(mContext);
+        verify(mWallpaperManager).isWallpaperSupported();
     }
 
     @Test
@@ -187,6 +191,26 @@
     }
 
     @Test
+    public void apply_disabledWallpaperService_dimWallpaperNotApplied() {
+        mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+        WallpaperManager disabledWallpaperService = mock(WallpaperManager.class);
+        when(mWallpaperManager.isWallpaperSupported()).thenReturn(false);
+        mContext.addMockSystemService(WallpaperManager.class, disabledWallpaperService);
+        mApplier = new DefaultDeviceEffectsApplier(mContext);
+        verify(mWallpaperManager).isWallpaperSupported();
+
+        ZenDeviceEffects effects = new ZenDeviceEffects.Builder()
+                .setShouldSuppressAmbientDisplay(true)
+                .setShouldDimWallpaper(true)
+                .setShouldDisplayGrayscale(true)
+                .setShouldUseNightMode(true)
+                .build();
+        mApplier.apply(effects, UPDATE_ORIGIN_USER);
+
+        verifyNoMoreInteractions(mWallpaperManager);
+    }
+
+    @Test
     public void apply_someEffects_onlyThoseEffectsApplied() {
         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GlobalSortKeyComparatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
index 5041779..d3e1b90 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
@@ -22,8 +22,8 @@
 import android.app.NotificationManager;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
index f077914..1194973 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
@@ -57,9 +57,9 @@
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.service.notification.StatusBarNotification;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArrayMap;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.R;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java
index ffc0dcd..a11d3f4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java
@@ -16,9 +16,6 @@
 package com.android.server.notification;
 
 import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
 import android.app.Notification;
@@ -27,8 +24,8 @@
 import android.app.NotificationManager;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
index e75afcc..a1c24f1 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
@@ -34,10 +34,9 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-
-import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyObject;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -84,13 +83,13 @@
 import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Pair;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.IAccessibilityManager;
 import android.view.accessibility.IAccessibilityManagerClient;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags;
@@ -103,10 +102,6 @@
 import com.android.server.lights.LogicalLight;
 import com.android.server.pm.PackageManagerService;
 
-import java.util.List;
-import java.util.Objects;
-
-import java.util.Set;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -118,6 +113,10 @@
 import org.mockito.MockitoAnnotations;
 import org.mockito.verification.VerificationMode;
 
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 @SuppressLint("GuardedBy")
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
index 7b16500..5aecac2 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
@@ -50,8 +50,8 @@
 import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
 import android.telecom.TelecomManager;
-import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryFilterTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryFilterTest.java
index 10bfcf1..6faa899 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryFilterTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryFilterTest.java
@@ -20,9 +20,9 @@
 import android.app.NotificationHistory;
 import android.app.NotificationHistory.HistoricalNotification;
 import android.graphics.drawable.Icon;
-import android.test.suitebuilder.annotation.SmallTest;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryProtoHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryProtoHelperTest.java
index 6eaf546..b234c3e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryProtoHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryProtoHelperTest.java
@@ -20,10 +20,10 @@
 import android.app.NotificationHistory;
 import android.app.NotificationHistory.HistoricalNotification;
 import android.graphics.drawable.Icon;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.text.TextUtils;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
index bf850cf..8fad01a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
@@ -56,8 +56,8 @@
 import android.service.notification.NotificationRankingUpdate;
 import android.service.notification.SnoozeCriterion;
 import android.service.notification.StatusBarNotification;
-import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
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 715c9d4..e3ea55a 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -87,10 +87,10 @@
 import static android.service.notification.Adjustment.KEY_IMPORTANCE;
 import static android.service.notification.Adjustment.KEY_TEXT_REPLIES;
 import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
-import static android.service.notification.Flags.FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS;
 import static android.service.notification.Condition.SOURCE_CONTEXT;
 import static android.service.notification.Condition.SOURCE_USER_ACTION;
 import static android.service.notification.Condition.STATE_TRUE;
+import static android.service.notification.Flags.FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS;
 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
@@ -247,7 +247,6 @@
 import android.service.notification.ZenPolicy;
 import android.telecom.TelecomManager;
 import android.telephony.TelephonyManager;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
@@ -263,6 +262,7 @@
 import android.widget.RemoteViews;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 
 import com.android.internal.R;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -14334,6 +14334,7 @@
 
     @Test
     @EnableFlags(android.app.Flags.FLAG_MODES_API)
+    @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
     public void requestInterruptionFilterFromListener_fromApp_doesNotSetGlobalZen()
             throws Exception {
         mService.setCallerIsNormalPackage();
@@ -14351,6 +14352,7 @@
 
     @Test
     @EnableFlags(android.app.Flags.FLAG_MODES_API)
+    @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
     public void requestInterruptionFilterFromListener_fromSystem_setsGlobalZen()
             throws Exception {
         mService.isSystemUid = true;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java
index 0222bfbf..b42df77 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java
@@ -22,7 +22,6 @@
 import static org.hamcrest.Matchers.instanceOf;
 import static org.junit.Assert.assertThat;
 import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -43,12 +42,12 @@
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
 import android.os.UserHandle;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableContext;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.server.UiServiceTestCase;
 
 import org.junit.Before;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotifyingAppTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotifyingAppTest.java
index 0c62831..30e851f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotifyingAppTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotifyingAppTest.java
@@ -20,8 +20,8 @@
 
 import android.os.Parcel;
 import android.service.notification.NotifyingApp;
-import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
index 2f52d5c..2d591ba 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
@@ -43,9 +43,9 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.ParceledListSlice;
 import android.permission.IPermissionManager;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Pair;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
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 8b55778..78fb570 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -115,7 +115,6 @@
 import android.provider.Settings.Secure;
 import android.service.notification.ConversationChannelWrapper;
 import android.service.notification.nano.RankingHelperProto;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.TestableContentResolver;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
@@ -128,6 +127,7 @@
 import android.util.proto.ProtoOutputStream;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
index 4217881..d2c6028 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -43,10 +43,10 @@
 import android.os.UserHandle;
 import android.os.Vibrator;
 import android.service.notification.StatusBarNotification;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.TestableContentResolver;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java
index 131aaa0..65ed7b6 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java
@@ -19,8 +19,7 @@
 
 import static java.util.concurrent.TimeUnit.HOURS;
 
-import android.test.suitebuilder.annotation.SmallTest;
-
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index 81c573d..70910b1 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -54,7 +54,6 @@
 import android.permission.PermissionManager;
 import android.telecom.TelecomManager;
 import android.telephony.TelephonyManager;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
@@ -63,6 +62,7 @@
 import android.util.Pair;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 
 import com.android.internal.config.sysui.TestableFlagResolver;
 import com.android.internal.logging.InstanceIdSequence;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
index 9ad007d..7b4229f6 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
@@ -23,9 +23,9 @@
 
 import android.service.notification.ScheduleCalendar;
 import android.service.notification.ZenModeConfig;
-import android.test.suitebuilder.annotation.SmallTest;
 
 import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
index 11cb150..a4fb16d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
@@ -36,9 +36,9 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.service.notification.StatusBarNotification;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.TestableLooper;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 1e3b728..dcd56e0 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -44,10 +44,10 @@
 import android.app.PendingIntent;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.IntArray;
 import android.util.Xml;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.modules.utils.TypedXmlPullParser;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
index 0564a73..cb44222 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
@@ -45,11 +45,11 @@
 import android.os.UserManager;
 import android.provider.ContactsContract;
 import android.service.notification.StatusBarNotification;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.text.SpannableString;
 import android.util.ArraySet;
 import android.util.LruCache;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/VibratorHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/VibratorHelperTest.java
index f135d16..0993bec 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/VibratorHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/VibratorHelperTest.java
@@ -24,8 +24,8 @@
 
 import android.os.VibrationEffect;
 import android.os.Vibrator;
-import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/VisibilityExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/VisibilityExtractorTest.java
index 3998129..6084153 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/VisibilityExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/VisibilityExtractorTest.java
@@ -18,17 +18,11 @@
 import static android.app.Notification.VISIBILITY_PRIVATE;
 import static android.app.Notification.VISIBILITY_SECRET;
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
-import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
 import static android.app.NotificationManager.VISIBILITY_NO_OVERRIDE;
 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS;
 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
 
 import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.Mockito.when;
 
@@ -36,15 +30,11 @@
 import android.app.Notification;
 import android.app.Notification.Builder;
 import android.app.NotificationChannel;
-import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
-import android.content.Intent;
-import android.graphics.drawable.Icon;
-import android.media.session.MediaSession;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
index 7d6e12c..b997f5d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
@@ -51,11 +51,12 @@
 import android.service.notification.ZenModeConfig;
 import android.service.notification.ZenPolicy;
 import android.telephony.TelephonyManager;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.ArraySet;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.util.NotificationMessagingUtil;
 import com.android.server.UiServiceTestCase;
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 8c50ef4..495e01a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -22,6 +22,7 @@
 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_DEACTIVATED;
 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_DISABLED;
 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ENABLED;
+import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_UNKNOWN;
 import static android.app.NotificationManager.INTERRUPTION_FILTER_ALARMS;
 import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL;
 import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE;
@@ -108,6 +109,7 @@
 import android.app.Flags;
 import android.app.NotificationManager;
 import android.app.NotificationManager.Policy;
+import android.app.compat.CompatChanges;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.pm.ActivityInfo;
@@ -141,7 +143,6 @@
 import android.service.notification.ZenModeConfig.ZenRule;
 import android.service.notification.ZenModeDiff;
 import android.service.notification.ZenPolicy;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.TestWithLooperRule;
 import android.testing.TestableLooper;
 import android.util.ArrayMap;
@@ -150,6 +151,8 @@
 import android.util.StatsEventTestUtils;
 import android.util.Xml;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.internal.R;
 import com.android.internal.config.sysui.TestableFlagResolver;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
@@ -4420,13 +4423,13 @@
     @EnableFlags(Flags.FLAG_MODES_API)
     public void updateAutomaticZenRule_nullDeviceEffectsUpdate() {
         // Adds a starting rule with empty zen policies and device effects
+        ZenDeviceEffects zde = new ZenDeviceEffects.Builder().setShouldUseNightMode(true).build();
         AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID)
-                .setDeviceEffects(new ZenDeviceEffects.Builder().build())
+                .setDeviceEffects(zde)
                 .build();
         // Adds the rule using the app, to avoid having any user modified bits set.
         String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
                 azrBase, UPDATE_ORIGIN_APP, "reason", Process.SYSTEM_UID);
-        AutomaticZenRule rule = mZenModeHelper.getAutomaticZenRule(ruleId);
 
         AutomaticZenRule azr = new AutomaticZenRule.Builder(azrBase)
                 // Sets Device Effects to null
@@ -4437,10 +4440,10 @@
         // user modified, it can be updated.
         mZenModeHelper.updateAutomaticZenRule(ruleId, azr, UPDATE_ORIGIN_APP, "reason",
                 Process.SYSTEM_UID);
-        rule = mZenModeHelper.getAutomaticZenRule(ruleId);
+        AutomaticZenRule rule = mZenModeHelper.getAutomaticZenRule(ruleId);
 
-        // When AZR's ZenDeviceEffects is null, the updated rule's device effects will be null.
-        assertThat(rule.getDeviceEffects()).isNull();
+        // When AZR's ZenDeviceEffects is null, the updated rule's device effects are kept.
+        assertThat(rule.getDeviceEffects()).isEqualTo(zde);
     }
 
     @Test
@@ -4673,7 +4676,11 @@
                 UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
 
         assertTrue(latch.await(500, TimeUnit.MILLISECONDS));
-        assertEquals(AUTOMATIC_RULE_STATUS_ACTIVATED, actualStatus[0]);
+        if (CompatChanges.isChangeEnabled(ZenModeHelper.SEND_ACTIVATION_AZR_STATUSES)) {
+            assertEquals(AUTOMATIC_RULE_STATUS_ACTIVATED, actualStatus[0]);
+        } else {
+            assertEquals(AUTOMATIC_RULE_STATUS_UNKNOWN, actualStatus[0]);
+        }
     }
 
     @Test
@@ -4714,7 +4721,11 @@
                 null, "", Process.SYSTEM_UID);
 
         assertTrue(latch.await(500, TimeUnit.MILLISECONDS));
-        assertEquals(AUTOMATIC_RULE_STATUS_DEACTIVATED, actualStatus[1]);
+        if (CompatChanges.isChangeEnabled(ZenModeHelper.SEND_ACTIVATION_AZR_STATUSES)) {
+            assertEquals(AUTOMATIC_RULE_STATUS_DEACTIVATED, actualStatus[1]);
+        } else {
+            assertEquals(AUTOMATIC_RULE_STATUS_UNKNOWN, actualStatus[1]);
+        }
     }
 
     @Test
@@ -4753,10 +4764,14 @@
 
         mZenModeHelper.setAutomaticZenRuleState(createdId,
                 new Condition(zenRule.getConditionId(), "", STATE_FALSE),
-                UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
+                UPDATE_ORIGIN_APP, Process.SYSTEM_UID);
 
         assertTrue(latch.await(500, TimeUnit.MILLISECONDS));
-        assertEquals(AUTOMATIC_RULE_STATUS_DEACTIVATED, actualStatus[1]);
+        if (CompatChanges.isChangeEnabled(ZenModeHelper.SEND_ACTIVATION_AZR_STATUSES)) {
+            assertEquals(AUTOMATIC_RULE_STATUS_DEACTIVATED, actualStatus[1]);
+        } else {
+            assertEquals(AUTOMATIC_RULE_STATUS_UNKNOWN, actualStatus[1]);
+        }
     }
 
     @Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
index 3a88294..6433b76 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
@@ -26,8 +26,8 @@
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.service.notification.ZenPolicy;
 import android.service.notification.nano.DNDPolicyProto;
-import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/GroupedAggregatedLogRecordsTest.java b/services/tests/vibrator/src/com/android/server/vibrator/GroupedAggregatedLogRecordsTest.java
new file mode 100644
index 0000000..038f1db
--- /dev/null
+++ b/services/tests/vibrator/src/com/android/server/vibrator/GroupedAggregatedLogRecordsTest.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.util.IndentingPrintWriter;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.vibrator.GroupedAggregatedLogRecords.AggregatedLogRecord;
+import com.android.server.vibrator.GroupedAggregatedLogRecords.SingleLogRecord;
+
+import org.junit.Test;
+
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class GroupedAggregatedLogRecordsTest {
+
+    private static final int AGGREGATION_TIME_LIMIT = 1000;
+    private static final int NO_AGGREGATION_TIME_LIMIT = 0;
+    private static final long PROTO_FIELD_ID = 1;
+    private static final int GROUP_1 = 1;
+    private static final int GROUP_2 = 2;
+    private static final int KEY_1 = 1;
+    private static final int KEY_2 = 2;
+
+    private static final IndentingPrintWriter WRITER = new IndentingPrintWriter(new StringWriter());
+    private static final ProtoOutputStream PROTO_OUTPUT_STREAM = new ProtoOutputStream();
+
+    private final List<TestSingleLogRecord> mTestRecords = new ArrayList<>();
+
+    @Test
+    public void record_noAggregation_keepsIndividualRecords() {
+        int sizeLimit = 10;
+        long createTime = 100;
+        TestGroupedAggregatedLogRecords records = new TestGroupedAggregatedLogRecords(
+                sizeLimit, NO_AGGREGATION_TIME_LIMIT, PROTO_FIELD_ID);
+
+        for (int i = 0; i < sizeLimit; i++) {
+            assertThat(records.add(createRecord(GROUP_1, KEY_1, createTime++))).isNull();
+        }
+
+        dumpRecords(records);
+        assertGroupHeadersWrittenOnce(records, GROUP_1);
+        assertRecordsInRangeWrittenOnce(0, sizeLimit);
+    }
+
+    @Test
+    public void record_sizeLimit_dropsOldestEntriesForNewOnes() {
+        long createTime = 100;
+        TestGroupedAggregatedLogRecords records = new TestGroupedAggregatedLogRecords(
+                /* sizeLimit= */ 2, NO_AGGREGATION_TIME_LIMIT, PROTO_FIELD_ID);
+
+        TestSingleLogRecord firstRecord = createRecord(GROUP_1, KEY_1, createTime++);
+        assertThat(records.add(firstRecord)).isNull();
+        assertThat(records.add(createRecord(GROUP_1, KEY_1, createTime++))).isNull();
+
+        // Adding third record drops first record
+        AggregatedLogRecord<TestSingleLogRecord> droppedRecord =
+                records.add(createRecord(GROUP_1, KEY_1, createTime++));
+        assertThat(droppedRecord).isNotNull();
+        assertThat(droppedRecord.getLatest()).isEqualTo(firstRecord);
+
+        dumpRecords(records);
+        assertGroupHeadersWrittenOnce(records, GROUP_1);
+        assertRecordsInRangeNotWritten(0, 1);  // First record not written
+        assertRecordsInRangeWrittenOnce(1, 3); // All newest records written
+    }
+
+    @Test
+    public void record_timeAggregation_aggregatesCloseRecordAndPrintsOnlyFirstAndLast() {
+        long createTime = 100;
+        TestGroupedAggregatedLogRecords records = new TestGroupedAggregatedLogRecords(
+                /* sizeLimit= */ 1, AGGREGATION_TIME_LIMIT, PROTO_FIELD_ID);
+
+        // No record dropped, all aggregated in a single entry
+        assertThat(records.add(createRecord(GROUP_1, KEY_1, createTime))).isNull();
+        assertThat(records.add(createRecord(GROUP_1, KEY_1, createTime + 1))).isNull();
+        assertThat(records.add(createRecord(GROUP_1, KEY_1,
+                createTime + AGGREGATION_TIME_LIMIT - 2))).isNull();
+        assertThat(records.add(createRecord(GROUP_1, KEY_1,
+                createTime + AGGREGATION_TIME_LIMIT - 1))).isNull();
+
+        dumpRecords(records);
+        assertGroupHeadersWrittenOnce(records, GROUP_1);
+        assertRecordsInRangeWrittenOnce(0, 1); // Writes first record
+        assertRecordsInRangeNotWritten(1, 3);  // Skips aggregated records in between
+        assertRecordsInRangeWrittenOnce(3, 4); // Writes last record
+    }
+
+    @Test
+    public void record_differentGroups_recordsKeptSeparate() {
+        long createTime = 100;
+        TestGroupedAggregatedLogRecords records = new TestGroupedAggregatedLogRecords(
+                /* sizeLimit= */ 1, AGGREGATION_TIME_LIMIT, PROTO_FIELD_ID);
+
+        // No record dropped, all kept in separate aggregated lists
+        assertThat(records.add(createRecord(GROUP_1, KEY_1, createTime++))).isNull();
+        assertThat(records.add(createRecord(GROUP_1, KEY_1, createTime++))).isNull();
+        assertThat(records.add(createRecord(GROUP_2, KEY_2, createTime++))).isNull();
+        assertThat(records.add(createRecord(GROUP_2, KEY_2, createTime++))).isNull();
+
+        dumpRecords(records);
+        assertGroupHeadersWrittenOnce(records, GROUP_1, GROUP_2);
+        assertRecordsInRangeWrittenOnce(0, 4);
+    }
+
+    @Test
+    public void record_sameGroupDifferentAggregationKeys_recordsNotAggregated() {
+        long createTime = 100;
+        TestGroupedAggregatedLogRecords records = new TestGroupedAggregatedLogRecords(
+                /* sizeLimit= */ 1, AGGREGATION_TIME_LIMIT, PROTO_FIELD_ID);
+
+        assertThat(records.add(createRecord(GROUP_1, KEY_1, createTime++))).isNull();
+
+        // Second record on same group with different key not aggregated, drops first record
+        AggregatedLogRecord<TestSingleLogRecord> droppedRecord =
+                records.add(createRecord(GROUP_1, KEY_2, createTime++));
+        assertThat(droppedRecord).isNotNull();
+        assertThat(droppedRecord.getLatest()).isEqualTo(mTestRecords.getFirst());
+
+        dumpRecords(records);
+        assertGroupHeadersWrittenOnce(records, GROUP_1);
+        assertRecordsInRangeNotWritten(0, 1);  // Skips first record that was dropped
+        assertRecordsInRangeWrittenOnce(1, 2); // Writes last record
+    }
+
+    @Test
+    public void record_sameGroupAndAggregationKeysDistantTimes_recordsNotAggregated() {
+        long createTime = 100;
+        TestGroupedAggregatedLogRecords records = new TestGroupedAggregatedLogRecords(
+                /* sizeLimit= */ 1, AGGREGATION_TIME_LIMIT, PROTO_FIELD_ID);
+
+        assertThat(records.add(createRecord(GROUP_1, KEY_1, createTime))).isNull();
+
+        // Second record after aggregation time limit not aggregated, drops first record
+        AggregatedLogRecord<TestSingleLogRecord> droppedRecord =
+                records.add(createRecord(GROUP_1, KEY_1, createTime + AGGREGATION_TIME_LIMIT));
+        assertThat(droppedRecord).isNotNull();
+        assertThat(droppedRecord.getLatest()).isEqualTo(mTestRecords.getFirst());
+
+        dumpRecords(records);
+        assertGroupHeadersWrittenOnce(records, GROUP_1);
+        assertRecordsInRangeNotWritten(0, 1);  // Skips first record that was dropped
+        assertRecordsInRangeWrittenOnce(1, 2); // Writes last record
+    }
+
+    private TestSingleLogRecord createRecord(int groupKey, int aggregateKey, long createTime) {
+        TestSingleLogRecord record = new TestSingleLogRecord(groupKey, aggregateKey, createTime);
+        mTestRecords.add(record);
+        return record;
+    }
+
+    private void dumpRecords(TestGroupedAggregatedLogRecords records) {
+        records.dump(WRITER);
+        records.dump(PROTO_OUTPUT_STREAM);
+    }
+
+    private void assertGroupHeadersWrittenOnce(TestGroupedAggregatedLogRecords records,
+            int... groupKeys) {
+        assertThat(records.dumpGroupKeys).containsExactlyElementsIn(
+                Arrays.stream(groupKeys).boxed().toList());
+    }
+
+    private void assertRecordsInRangeWrittenOnce(int startIndexInclusive, int endIndexExclusive) {
+        for (int i = startIndexInclusive; i < endIndexExclusive; i++) {
+            assertWithMessage("record index=" + i).that(mTestRecords.get(i).dumpTextCount)
+                    .isEqualTo(1);
+            assertWithMessage("record index=" + i).that(mTestRecords.get(i).dumpProtoFieldIds)
+                    .containsExactly(PROTO_FIELD_ID);
+        }
+    }
+
+    private void assertRecordsInRangeNotWritten(int startIndexInclusive, int endIndexExclusive) {
+        for (int i = startIndexInclusive; i < endIndexExclusive; i++) {
+            assertWithMessage("record index=" + i).that(mTestRecords.get(i).dumpTextCount)
+                    .isEqualTo(0);
+            assertWithMessage("record index=" + i).that(mTestRecords.get(i).dumpProtoFieldIds)
+                    .isEmpty();
+        }
+    }
+
+    private static final class TestGroupedAggregatedLogRecords
+            extends GroupedAggregatedLogRecords<TestSingleLogRecord> {
+
+        public final List<Integer> dumpGroupKeys = new ArrayList<>();
+
+        private final long mProtoFieldId;
+
+        TestGroupedAggregatedLogRecords(int sizeLimit, int aggregationTimeLimitMs,
+                long protoFieldId) {
+            super(sizeLimit, aggregationTimeLimitMs);
+            mProtoFieldId = protoFieldId;
+        }
+
+        @Override
+        void dumpGroupHeader(IndentingPrintWriter pw, int groupKey) {
+            dumpGroupKeys.add(groupKey);
+        }
+
+        @Override
+        long findGroupKeyProtoFieldId(int groupKey) {
+            return mProtoFieldId;
+        }
+    }
+
+    private static final class TestSingleLogRecord implements SingleLogRecord {
+        public final List<Long> dumpProtoFieldIds = new ArrayList<>();
+        public int dumpTextCount = 0;
+
+        private final int mGroupKey;
+        private final int mAggregateKey;
+        private final long mCreateTime;
+
+        TestSingleLogRecord(int groupKey, int aggregateKey, long createTime) {
+            mGroupKey = groupKey;
+            mAggregateKey = aggregateKey;
+            mCreateTime = createTime;
+        }
+
+        @Override
+        public int getGroupKey() {
+            return mGroupKey;
+        }
+
+        @Override
+        public long getCreateUptimeMs() {
+            return mCreateTime;
+        }
+
+        @Override
+        public boolean mayAggregate(SingleLogRecord record) {
+            if (record instanceof TestSingleLogRecord param) {
+                return mAggregateKey == param.mAggregateKey;
+            }
+            return false;
+        }
+
+        @Override
+        public void dump(IndentingPrintWriter pw) {
+            dumpTextCount++;
+        }
+
+        @Override
+        public void dump(ProtoOutputStream proto, long fieldId) {
+            dumpProtoFieldIds.add(fieldId);
+        }
+    }
+}
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 3d0dca0..e3d4596 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java
@@ -17,9 +17,11 @@
 package com.android.server.vibrator;
 
 import static android.os.VibrationAttributes.CATEGORY_KEYBOARD;
+import static android.os.VibrationAttributes.CATEGORY_UNKNOWN;
 import static android.os.VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
 import static android.os.VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF;
 import static android.os.VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE;
+import static android.os.VibrationAttributes.USAGE_TOUCH;
 import static android.os.VibrationEffect.Composition.PRIMITIVE_CLICK;
 import static android.os.VibrationEffect.Composition.PRIMITIVE_TICK;
 import static android.os.VibrationEffect.EFFECT_CLICK;
@@ -285,7 +287,8 @@
         HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
 
         VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
-                SAFE_MODE_ENABLED, /* bypassVibrationIntensitySetting= */ false);
+                SAFE_MODE_ENABLED, /* bypassVibrationIntensitySetting= */ false,
+                false /* fromIme*/);
 
         assertThat(attrs.isFlagSet(FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)).isFalse();
     }
@@ -295,7 +298,7 @@
         HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
 
         VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
-                SAFE_MODE_ENABLED, /* bypassVibrationIntensitySetting= */ true);
+                SAFE_MODE_ENABLED, /* bypassVibrationIntensitySetting= */ true, false /* fromIme*/);
 
         assertThat(attrs.isFlagSet(FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)).isTrue();
     }
@@ -307,7 +310,7 @@
 
         for (int effectId : SCROLL_FEEDBACK_CONSTANTS) {
             VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
-                    effectId, /* bypassVibrationIntensitySetting= */ false);
+                    effectId, /* bypassVibrationIntensitySetting= */ false, false /* fromIme*/);
             assertWithMessage("Expected FLAG_BYPASS_INTERRUPTION_POLICY for effect " + effectId)
                    .that(attrs.isFlagSet(FLAG_BYPASS_INTERRUPTION_POLICY)).isTrue();
         }
@@ -320,40 +323,59 @@
 
         for (int effectId : SCROLL_FEEDBACK_CONSTANTS) {
             VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
-                    effectId, /* bypassVibrationIntensitySetting= */ false);
+                    effectId, /* bypassVibrationIntensitySetting= */ false, false /* fromIme*/);
             assertWithMessage("Expected no FLAG_BYPASS_INTERRUPTION_POLICY for effect " + effectId)
                    .that(attrs.isFlagSet(FLAG_BYPASS_INTERRUPTION_POLICY)).isFalse();
         }
     }
 
     @Test
-    public void testVibrationAttribute_keyboardCategoryOff_notUseKeyboardCategory() {
+    public void testVibrationAttribute_keyboardCategoryOff_isIme_notUseKeyboardCategory() {
         mSetFlagsRule.disableFlags(Flags.FLAG_KEYBOARD_CATEGORY_ENABLED);
         HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
 
         for (int effectId : KEYBOARD_FEEDBACK_CONSTANTS) {
             VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
-                    effectId, /* bypassVibrationIntensitySetting= */ false);
+                    effectId, /* bypassVibrationIntensitySetting= */ false, true /* fromIme*/);
+            assertWithMessage("Expected USAGE_TOUCH for effect " + effectId)
+                    .that(attrs.getUsage()).isEqualTo(USAGE_TOUCH);
             assertWithMessage("Expected no CATEGORY_KEYBOARD for effect " + effectId)
-                    .that(attrs.getCategory()).isEqualTo(0);
+                    .that(attrs.getCategory()).isEqualTo(CATEGORY_UNKNOWN);
         }
     }
 
     @Test
-    public void testVibrationAttribute_keyboardCategoryOn_useKeyboardCategory() {
+    public void testVibrationAttribute_keyboardCategoryOn_notIme_notUseKeyboardCategory() {
         mSetFlagsRule.enableFlags(Flags.FLAG_KEYBOARD_CATEGORY_ENABLED);
         HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
 
         for (int effectId : KEYBOARD_FEEDBACK_CONSTANTS) {
             VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
-                    effectId, /* bypassVibrationIntensitySetting= */ false);
+                    effectId, /* bypassVibrationIntensitySetting= */ false, false /* fromIme*/);
+            assertWithMessage("Expected USAGE_TOUCH for effect " + effectId)
+                    .that(attrs.getUsage()).isEqualTo(USAGE_TOUCH);
+            assertWithMessage("Expected CATEGORY_KEYBOARD for effect " + effectId)
+                    .that(attrs.getCategory()).isEqualTo(CATEGORY_UNKNOWN);
+        }
+    }
+
+    @Test
+    public void testVibrationAttribute_keyboardCategoryOn_isIme_useKeyboardCategory() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_KEYBOARD_CATEGORY_ENABLED);
+        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
+
+        for (int effectId : KEYBOARD_FEEDBACK_CONSTANTS) {
+            VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
+                    effectId, /* bypassVibrationIntensitySetting= */ false, true /* fromIme*/);
+            assertWithMessage("Expected USAGE_TOUCH for effect " + effectId)
+                    .that(attrs.getUsage()).isEqualTo(USAGE_TOUCH);
             assertWithMessage("Expected CATEGORY_KEYBOARD for effect " + effectId)
                     .that(attrs.getCategory()).isEqualTo(CATEGORY_KEYBOARD);
         }
     }
 
     @Test
-    public void testVibrationAttribute_noFixAmplitude_keyboardCategoryOn_noBypassIntensityScale() {
+    public void testVibrationAttribute_noFixAmplitude_notBypassIntensityScale() {
         mSetFlagsRule.enableFlags(Flags.FLAG_KEYBOARD_CATEGORY_ENABLED);
         mockVibratorPrimitiveSupport(PRIMITIVE_CLICK, PRIMITIVE_TICK);
         mockKeyboardVibrationFixedAmplitude(-1);
@@ -361,7 +383,7 @@
 
         for (int effectId : KEYBOARD_FEEDBACK_CONSTANTS) {
             VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
-                    effectId, /* bypassVibrationIntensitySetting= */ false);
+                    effectId, /* bypassVibrationIntensitySetting= */ false, true /* fromIme*/);
             assertWithMessage("Expected no FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE for effect "
                     + effectId)
                     .that(attrs.isFlagSet(FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE)).isFalse();
@@ -369,7 +391,7 @@
     }
 
     @Test
-    public void testVibrationAttribute_fixAmplitude_keyboardCategoryOn_bypassIntensityScale() {
+    public void testVibrationAttribute_notIme_notBypassIntensityScale() {
         mSetFlagsRule.enableFlags(Flags.FLAG_KEYBOARD_CATEGORY_ENABLED);
         mockVibratorPrimitiveSupport(PRIMITIVE_CLICK, PRIMITIVE_TICK);
         mockKeyboardVibrationFixedAmplitude(KEYBOARD_VIBRATION_FIXED_AMPLITUDE);
@@ -377,7 +399,23 @@
 
         for (int effectId : KEYBOARD_FEEDBACK_CONSTANTS) {
             VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
-                    effectId, /* bypassVibrationIntensitySetting= */ false);
+                    effectId, /* bypassVibrationIntensitySetting= */ false, false /* fromIme*/);
+            assertWithMessage("Expected no FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE for effect "
+                    + effectId)
+                    .that(attrs.isFlagSet(FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE)).isFalse();
+        }
+    }
+
+    @Test
+    public void testVibrationAttribute_fixAmplitude_isIme_bypassIntensityScale() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_KEYBOARD_CATEGORY_ENABLED);
+        mockVibratorPrimitiveSupport(PRIMITIVE_CLICK, PRIMITIVE_TICK);
+        mockKeyboardVibrationFixedAmplitude(KEYBOARD_VIBRATION_FIXED_AMPLITUDE);
+        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
+
+        for (int effectId : KEYBOARD_FEEDBACK_CONSTANTS) {
+            VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
+                    effectId, /* bypassVibrationIntensitySetting= */ false, true /* fromIme*/);
             assertWithMessage("Expected FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE for effect "
                     + effectId)
                     .that(attrs.isFlagSet(FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE)).isTrue();
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationScalerTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationScalerTest.java
index 3e59878..b264435 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationScalerTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationScalerTest.java
@@ -117,32 +117,32 @@
     }
 
     @Test
-    public void testGetExternalVibrationScale() {
+    public void testGetScaleLevel() {
         setDefaultIntensity(USAGE_TOUCH, Vibrator.VIBRATION_INTENSITY_LOW);
         setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_HIGH);
         assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_VERY_HIGH,
-                mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH));
+                mVibrationScaler.getScaleLevel(USAGE_TOUCH));
 
         setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_MEDIUM);
         assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_HIGH,
-                mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH));
+                mVibrationScaler.getScaleLevel(USAGE_TOUCH));
 
         setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_LOW);
         assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_NONE,
-                mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH));
+                mVibrationScaler.getScaleLevel(USAGE_TOUCH));
 
         setDefaultIntensity(USAGE_TOUCH, VIBRATION_INTENSITY_MEDIUM);
         assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_LOW,
-                mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH));
+                mVibrationScaler.getScaleLevel(USAGE_TOUCH));
 
         setDefaultIntensity(USAGE_TOUCH, VIBRATION_INTENSITY_HIGH);
         assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_VERY_LOW,
-                mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH));
+                mVibrationScaler.getScaleLevel(USAGE_TOUCH));
 
         setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
         // Vibration setting being bypassed will use default setting and not scale.
         assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_NONE,
-                mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH));
+                mVibrationScaler.getScaleLevel(USAGE_TOUCH));
     }
 
     @Test
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java
index 417fbd0..3799abc 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java
@@ -38,10 +38,10 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.RemoteException;
 import android.os.test.TestLooper;
 import android.util.SparseArray;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.internal.util.ArrayUtils;
@@ -67,6 +67,7 @@
     @Mock
     private PackageManagerInternal mPackageManagerInternalMock;
 
+    private TestLooper mTestLooper;
     private FakeVibratorController mFakeVibratorController;
     private VibratorControlService mVibratorControlService;
     private VibrationSettings mVibrationSettings;
@@ -74,6 +75,7 @@
 
     @Before
     public void setUp() throws Exception {
+        mTestLooper = new TestLooper();
         when(mPackageManagerInternalMock.getSystemUiServiceComponent())
                 .thenReturn(new ComponentName("", ""));
         LocalServices.removeServiceForTest(PackageManagerInternal.class);
@@ -83,21 +85,21 @@
         mVibrationSettings = new VibrationSettings(
                 ApplicationProvider.getApplicationContext(), new Handler(testLooper.getLooper()));
 
-        mFakeVibratorController = new FakeVibratorController();
-        mVibratorControlService = new VibratorControlService(new VibratorControllerHolder(),
+        mFakeVibratorController = new FakeVibratorController(mTestLooper.getLooper());
+        mVibratorControlService = new VibratorControlService(
+                InstrumentationRegistry.getContext(), new VibratorControllerHolder(),
                 mMockVibrationScaler, mVibrationSettings, mLock);
     }
 
     @Test
-    public void testRegisterVibratorController() throws RemoteException {
+    public void testRegisterVibratorController() {
         mVibratorControlService.registerVibratorController(mFakeVibratorController);
 
         assertThat(mFakeVibratorController.isLinkedToDeath).isTrue();
     }
 
     @Test
-    public void testUnregisterVibratorController_providingTheRegisteredController_performsRequest()
-            throws RemoteException {
+    public void testUnregisterVibratorController_providingRegisteredController_performsRequest() {
         mVibratorControlService.registerVibratorController(mFakeVibratorController);
         mVibratorControlService.unregisterVibratorController(mFakeVibratorController);
 
@@ -106,20 +108,18 @@
     }
 
     @Test
-    public void testUnregisterVibratorController_providingAnInvalidController_ignoresRequest()
-            throws RemoteException {
-        FakeVibratorController fakeController1 = new FakeVibratorController();
-        FakeVibratorController fakeController2 = new FakeVibratorController();
-        mVibratorControlService.registerVibratorController(fakeController1);
-        mVibratorControlService.unregisterVibratorController(fakeController2);
+    public void testUnregisterVibratorController_providingAnInvalidController_ignoresRequest() {
+        FakeVibratorController controller1 = new FakeVibratorController(mTestLooper.getLooper());
+        FakeVibratorController controller2 = new FakeVibratorController(mTestLooper.getLooper());
+        mVibratorControlService.registerVibratorController(controller1);
+        mVibratorControlService.unregisterVibratorController(controller2);
 
         verifyZeroInteractions(mMockVibrationScaler);
-        assertThat(fakeController1.isLinkedToDeath).isTrue();
+        assertThat(controller1.isLinkedToDeath).isTrue();
     }
 
     @Test
-    public void testOnRequestVibrationParamsComplete_cachesAdaptiveHapticsScalesCorrectly()
-            throws RemoteException {
+    public void testOnRequestVibrationParamsComplete_cachesAdaptiveHapticsScalesCorrectly() {
         mVibratorControlService.registerVibratorController(mFakeVibratorController);
         int timeoutInMillis = 10;
         CompletableFuture<Void> future =
@@ -146,8 +146,7 @@
     }
 
     @Test
-    public void testOnRequestVibrationParamsComplete_withIncorrectToken_ignoresRequest()
-            throws RemoteException, InterruptedException {
+    public void testOnRequestVibrationParamsComplete_withIncorrectToken_ignoresRequest() {
         mVibratorControlService.registerVibratorController(mFakeVibratorController);
         int timeoutInMillis = 10;
         CompletableFuture<Void> unusedFuture =
@@ -165,8 +164,7 @@
     }
 
     @Test
-    public void testSetVibrationParams_cachesAdaptiveHapticsScalesCorrectly()
-            throws RemoteException {
+    public void testSetVibrationParams_cachesAdaptiveHapticsScalesCorrectly() {
         mVibratorControlService.registerVibratorController(mFakeVibratorController);
         SparseArray<Float> vibrationScales = new SparseArray<>();
         vibrationScales.put(ScaleParam.TYPE_ALARM, 0.7f);
@@ -185,8 +183,7 @@
     }
 
     @Test
-    public void testSetVibrationParams_withUnregisteredController_ignoresRequest()
-            throws RemoteException {
+    public void testSetVibrationParams_withUnregisteredController_ignoresRequest() {
         SparseArray<Float> vibrationScales = new SparseArray<>();
         vibrationScales.put(ScaleParam.TYPE_ALARM, 0.7f);
         vibrationScales.put(ScaleParam.TYPE_NOTIFICATION, 0.4f);
@@ -199,8 +196,7 @@
     }
 
     @Test
-    public void testClearVibrationParams_clearsCachedAdaptiveHapticsScales()
-            throws RemoteException {
+    public void testClearVibrationParams_clearsCachedAdaptiveHapticsScales() {
         mVibratorControlService.registerVibratorController(mFakeVibratorController);
         int types = buildVibrationTypesMask(ScaleParam.TYPE_ALARM, ScaleParam.TYPE_NOTIFICATION);
 
@@ -214,8 +210,7 @@
     }
 
     @Test
-    public void testClearVibrationParams_withUnregisteredController_ignoresRequest()
-            throws RemoteException {
+    public void testClearVibrationParams_withUnregisteredController_ignoresRequest() {
         mVibratorControlService.clearVibrationParams(ScaleParam.TYPE_ALARM,
                 mFakeVibratorController);
 
@@ -223,8 +218,7 @@
     }
 
     @Test
-    public void testRequestVibrationParams_createsFutureRequestProperly()
-            throws RemoteException {
+    public void testRequestVibrationParams_createsFutureRequestProperly() {
         int timeoutInMillis = 10;
         mVibratorControlService.registerVibratorController(mFakeVibratorController);
         CompletableFuture<Void> future =
@@ -241,8 +235,7 @@
     }
 
     @Test
-    public void testShouldRequestVibrationParams_returnsTrueForVibrationsThatShouldRequestParams()
-            throws RemoteException {
+    public void testShouldRequestVibrationParams_returnsTrueForVibrationsThatShouldRequestParams() {
         int[] vibrations =
                 new int[]{USAGE_ALARM, USAGE_RINGTONE, USAGE_MEDIA, USAGE_TOUCH, USAGE_NOTIFICATION,
                         USAGE_HARDWARE_FEEDBACK, USAGE_UNKNOWN, USAGE_COMMUNICATION_REQUEST};
@@ -256,8 +249,7 @@
     }
 
     @Test
-    public void testShouldRequestVibrationParams_unregisteredVibratorController_returnsFalse()
-            throws RemoteException {
+    public void testShouldRequestVibrationParams_unregisteredVibratorController_returnsFalse() {
         int[] vibrations =
                 new int[]{USAGE_ALARM, USAGE_RINGTONE, USAGE_MEDIA, USAGE_TOUCH, USAGE_NOTIFICATION,
                         USAGE_HARDWARE_FEEDBACK, USAGE_UNKNOWN, USAGE_COMMUNICATION_REQUEST};
@@ -267,7 +259,7 @@
         }
     }
 
-    private int buildVibrationTypesMask(int... types) {
+    private static int buildVibrationTypesMask(int... types) {
         int typesMask = 0;
         for (int type : types) {
             typesMask |= type;
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java
index 79abe21..db823d6 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java
@@ -18,23 +18,26 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import android.os.RemoteException;
+import android.os.test.TestLooper;
 
 import org.junit.Before;
 import org.junit.Test;
 
 public class VibratorControllerHolderTest {
 
-    private final FakeVibratorController mFakeVibratorController = new FakeVibratorController();
+    private TestLooper mTestLooper;
+    private FakeVibratorController mFakeVibratorController;
     private VibratorControllerHolder mVibratorControllerHolder;
 
     @Before
     public void setUp() throws Exception {
+        mTestLooper = new TestLooper();
+        mFakeVibratorController = new FakeVibratorController(mTestLooper.getLooper());
         mVibratorControllerHolder = new VibratorControllerHolder();
     }
 
     @Test
-    public void testSetVibratorController_linksVibratorControllerToDeath() throws RemoteException {
+    public void testSetVibratorController_linksVibratorControllerToDeath() {
         mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
         assertThat(mVibratorControllerHolder.getVibratorController())
                 .isEqualTo(mFakeVibratorController);
@@ -42,8 +45,7 @@
     }
 
     @Test
-    public void testSetVibratorController_setControllerToNull_unlinksVibratorControllerToDeath()
-            throws RemoteException {
+    public void testSetVibratorController_setControllerToNull_unlinksVibratorControllerToDeath() {
         mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
         mVibratorControllerHolder.setVibratorController(null);
         assertThat(mFakeVibratorController.isLinkedToDeath).isFalse();
@@ -51,8 +53,7 @@
     }
 
     @Test
-    public void testBinderDied_withValidController_unlinksVibratorControllerToDeath()
-            throws RemoteException {
+    public void testBinderDied_withValidController_unlinksVibratorControllerToDeath() {
         mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
         mVibratorControllerHolder.binderDied(mFakeVibratorController);
         assertThat(mFakeVibratorController.isLinkedToDeath).isFalse();
@@ -60,10 +61,10 @@
     }
 
     @Test
-    public void testBinderDied_withInvalidController_ignoresRequest()
-            throws RemoteException {
+    public void testBinderDied_withInvalidController_ignoresRequest() {
         mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
-        FakeVibratorController imposterVibratorController = new FakeVibratorController();
+        FakeVibratorController imposterVibratorController =
+                new FakeVibratorController(mTestLooper.getLooper());
         mVibratorControllerHolder.binderDied(imposterVibratorController);
         assertThat(mFakeVibratorController.isLinkedToDeath).isTrue();
         assertThat(mVibratorControllerHolder.getVibratorController())
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 ed89ccf..1ea90f5 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -97,7 +97,6 @@
 import android.view.flags.Flags;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
 
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.FrameworkStatsLog;
@@ -117,6 +116,7 @@
 import org.mockito.junit.MockitoRule;
 
 import java.time.Duration;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -128,9 +128,7 @@
 public class VibratorManagerServiceTest {
 
     private static final int TEST_TIMEOUT_MILLIS = 1_000;
-    // Time to allow for a cancellation to complete (notably including system ramp down), but not so
-    // long that tests easily get really slow or flaky. If a vibration is close to this, it should
-    // be cancelled in the body of the individual test.
+    // Time to allow for a cancellation to complete and the vibrators to become idle.
     private static final int CLEANUP_TIMEOUT_MILLIS = 100;
     private static final int UID = Process.ROOT_UID;
     private static final int VIRTUAL_DEVICE_ID = 1;
@@ -186,8 +184,8 @@
     private AudioManager mAudioManagerMock;
 
     private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>();
-
-    private SparseArray<VibrationEffect>  mHapticFeedbackVibrationMap = new SparseArray<>();
+    private final SparseArray<VibrationEffect>  mHapticFeedbackVibrationMap = new SparseArray<>();
+    private final List<HalVibration> mPendingVibrations = new ArrayList<>();
 
     private VibratorManagerService mService;
     private Context mContextSpy;
@@ -207,7 +205,7 @@
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
         mInputManagerGlobalSession = InputManagerGlobal.createTestSession(mIInputManagerMock);
         mVibrationConfig = new VibrationConfig(mContextSpy.getResources());
-        mFakeVibratorController = new FakeVibratorController();
+        mFakeVibratorController = new FakeVibratorController(mTestLooper.getLooper());
 
         ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
         when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
@@ -253,12 +251,15 @@
     @After
     public void tearDown() throws Exception {
         if (mService != null) {
-            // Wait until all vibrators have stopped vibrating, with a bit of flexibility for tests
-            // that just do a click or have cancelled at the end (waiting for ramp-down).
-            //
-            // Note: if a test is flaky here, check whether a VibrationEffect duration is close to
-            // CLEANUP_TIMEOUT_MILLIS - in which case it's probably best to just cancel that effect
-            // explicitly at the end of the test case (rather than letting it run and race flakily).
+            if (!mPendingVibrations.stream().allMatch(HalVibration::hasEnded)) {
+                // Cancel any pending vibration from tests.
+                cancelVibrate(mService);
+                for (HalVibration vibration : mPendingVibrations) {
+                    vibration.waitForEnd();
+                }
+            }
+            // Wait until all vibrators have stopped vibrating, waiting for ramp-down.
+            // Note: if a test is flaky here something is wrong with the vibration finalization.
             assertTrue(waitUntil(s -> {
                 for (int vibratorId : mService.getVibratorIds()) {
                     if (s.isVibrating(vibratorId)) {
@@ -266,7 +267,7 @@
                     }
                 }
                 return true;
-            }, mService, CLEANUP_TIMEOUT_MILLIS));
+            }, mService, mVibrationConfig.getRampDownDurationMs() + CLEANUP_TIMEOUT_MILLIS));
         }
 
         LocalServices.removeServiceForTest(PackageManagerInternal.class);
@@ -323,21 +324,26 @@
                                     (VibratorManagerService.ExternalVibratorService) service;
                         } else if (service instanceof VibratorControlService) {
                             mVibratorControlService = (VibratorControlService) service;
+                            mFakeVibratorController.setVibratorControlService(
+                                    mVibratorControlService);
                         }
                     }
 
+                    @Override
                     HapticFeedbackVibrationProvider createHapticFeedbackVibrationProvider(
                             Resources resources, VibratorInfo vibratorInfo) {
                         return new HapticFeedbackVibrationProvider(
                                 resources, vibratorInfo, mHapticFeedbackVibrationMap);
                     }
 
+                    @Override
                     VibratorControllerHolder createVibratorControllerHolder() {
                         VibratorControllerHolder holder = new VibratorControllerHolder();
                         holder.setVibratorController(mFakeVibratorController);
                         return holder;
                     }
 
+                    @Override
                     boolean isServiceDeclared(String name) {
                         return true;
                     }
@@ -486,8 +492,9 @@
         InOrder inOrderVerifier = inOrder(listenerMock);
         // First notification done when listener is registered.
         inOrderVerifier.verify(listenerMock).onVibrating(eq(false));
+        // Vibrator on notification done before vibration ended, no need to wait.
         inOrderVerifier.verify(listenerMock).onVibrating(eq(true));
-        // The last notification is after the vibration has completed.
+        // Vibrator off notification done after vibration completed, wait for notification.
         inOrderVerifier.verify(listenerMock, timeout(TEST_TIMEOUT_MILLIS)).onVibrating(eq(false));
         inOrderVerifier.verifyNoMoreInteractions();
 
@@ -517,6 +524,7 @@
         InOrder inOrderVerifier = inOrder(listenerMock);
         // First notification done when listener is registered.
         inOrderVerifier.verify(listenerMock).onVibrating(eq(false));
+        // Vibrator on notification done before vibration ended, no need to wait.
         inOrderVerifier.verify(listenerMock).onVibrating(eq(true));
         inOrderVerifier.verify(listenerMock, atLeastOnce()).asBinder(); // unregister
         inOrderVerifier.verifyNoMoreInteractions();
@@ -541,7 +549,6 @@
         verify(listeners[0]).onVibrating(eq(true));
         verify(listeners[1]).onVibrating(eq(true));
         verify(listeners[2], never()).onVibrating(eq(true));
-        cancelVibrate(service); // Clean up long-ish effect.
     }
 
     @Test
@@ -889,21 +896,24 @@
                         eq(AudioAttributes.USAGE_UNKNOWN), anyInt(), anyString());
     }
 
-    @FlakyTest
     @Test
     public void vibrate_withOngoingRepeatingVibration_ignoresEffect() throws Exception {
         mockVibrators(1);
-        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect repeatingEffect = VibrationEffect.createWaveform(
-                new long[]{10_000, 10_000}, new int[]{128, 255}, 1);
-        vibrate(service, repeatingEffect, new VibrationAttributes.Builder().setUsage(
-                VibrationAttributes.USAGE_UNKNOWN).build());
+                new long[]{10, 10_000}, new int[]{128, 255}, 1);
+        vibrate(service, repeatingEffect,
+                new VibrationAttributes.Builder()
+                        .setUsage(VibrationAttributes.USAGE_UNKNOWN)
+                        .build());
 
-        // VibrationThread will start this vibration async, wait until it has started.
-        assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
-                service, TEST_TIMEOUT_MILLIS));
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service,
+                TEST_TIMEOUT_MILLIS));
 
         vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
                 HAPTIC_FEEDBACK_ATTRS);
@@ -914,9 +924,8 @@
         // The second vibration shouldn't have recorded that the vibrators were turned on.
         verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong());
         // No segment played is the prebaked CLICK from the second vibration.
-        assertFalse(mVibratorProviders.get(1).getAllEffectSegments().stream()
+        assertFalse(fakeVibrator.getAllEffectSegments().stream()
                 .anyMatch(PrebakedSegment.class::isInstance));
-        cancelVibrate(service);  // Clean up repeating effect.
     }
 
     @Test
@@ -930,11 +939,13 @@
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect repeatingEffect = VibrationEffect.createWaveform(
-                new long[]{10, 10_000}, new int[]{255, 0}, 1);
+                new long[]{10, 10_000}, new int[]{128, 255}, 1);
         vibrate(service, repeatingEffect, ALARM_ATTRS);
 
-        // VibrationThread will start this vibration async, wait until the off waveform step.
-        assertTrue(waitUntil(s -> fakeVibrator.getOffCount() > 0, service, TEST_TIMEOUT_MILLIS));
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service,
+                TEST_TIMEOUT_MILLIS));
 
         // Cancel vibration right before requesting a new one.
         // This should trigger slow IVibrator.off before setting the vibration status to cancelled.
@@ -942,6 +953,8 @@
         vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
                 ALARM_ATTRS);
 
+        // The second vibration should have recorded that the vibrators were turned on.
+        verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong());
         // Check that second vibration was played.
         assertTrue(fakeVibrator.getAllEffectSegments().stream()
                 .anyMatch(PrebakedSegment.class::isInstance));
@@ -951,45 +964,47 @@
     public void vibrate_withNewSameImportanceVibrationAndBothRepeating_cancelsOngoingEffect()
             throws Exception {
         mockVibrators(1);
-        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect repeatingEffect = VibrationEffect.createWaveform(
-                new long[]{10_000, 10_000}, new int[]{128, 255}, 1);
+                new long[]{10, 10_000}, new int[]{128, 255}, 1);
         vibrate(service, repeatingEffect, ALARM_ATTRS);
 
-        // VibrationThread will start this vibration async, wait until it has started.
-        assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
-                service, TEST_TIMEOUT_MILLIS));
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service,
+                TEST_TIMEOUT_MILLIS));
 
         VibrationEffect repeatingEffect2 = VibrationEffect.createWaveform(
-                new long[]{10_000, 10_000}, new int[]{128, 255}, 1);
+                new long[]{10, 10_000}, new int[]{255, 128}, 1);
         vibrate(service, repeatingEffect2, ALARM_ATTRS);
 
-        // VibrationThread will start this vibration async, so wait before checking it started.
-        assertTrue(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() == 2,
-                service, TEST_TIMEOUT_MILLIS));
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 4, service,
+                TEST_TIMEOUT_MILLIS));
 
         // The second vibration should have recorded that the vibrators were turned on.
         verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong());
-
-        cancelVibrate(service);  // Clean up repeating effect.
     }
 
-    @FlakyTest
     @Test
     public void vibrate_withNewSameImportanceVibrationButOngoingIsRepeating_ignoreNewVibration()
             throws Exception {
         mockVibrators(1);
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect repeatingEffect = VibrationEffect.createWaveform(
-                new long[]{10, 10_000}, new int[]{255, 0}, 1);
+                new long[]{10, 10_000}, new int[]{128, 255}, 1);
         vibrate(service, repeatingEffect, ALARM_ATTRS);
 
-        // VibrationThread will start this vibration async, wait until it has started.
-        assertTrue(waitUntil(s -> !fakeVibrator.getAllEffectSegments().isEmpty(), service,
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service,
                 TEST_TIMEOUT_MILLIS));
 
         vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
@@ -998,53 +1013,55 @@
         // The second vibration shouldn't have recorded that the vibrators were turned on.
         verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong());
         // The second vibration shouldn't have played any prebaked segment.
-        assertFalse(mVibratorProviders.get(1).getAllEffectSegments().stream()
+        assertFalse(fakeVibrator.getAllEffectSegments().stream()
                 .anyMatch(PrebakedSegment.class::isInstance));
-        cancelVibrate(service);  // Clean up long effect.
     }
 
     @Test
     public void vibrate_withNewUnknownUsageVibrationAndRepeating_cancelsOngoingEffect()
             throws Exception {
         mockVibrators(1);
+        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect repeatingEffect = VibrationEffect.createWaveform(
-                new long[]{10_000, 10_000}, new int[]{128, 255}, 1);
+                new long[]{10, 10_000}, new int[]{128, 255}, 1);
         vibrate(service, repeatingEffect, ALARM_ATTRS);
 
-        // VibrationThread will start this vibration async, wait until it has started.
-        assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
-                service, TEST_TIMEOUT_MILLIS));
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service,
+                TEST_TIMEOUT_MILLIS));
 
         VibrationEffect repeatingEffect2 = VibrationEffect.createWaveform(
-                new long[]{10_000, 10_000}, new int[]{128, 255}, 1);
+                new long[]{10, 10_000}, new int[]{255, 128}, 1);
         vibrate(service, repeatingEffect2, UNKNOWN_ATTRS);
 
-        // VibrationThread will start this vibration async, so wait before checking it started.
-        assertTrue(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() == 2,
-                service, TEST_TIMEOUT_MILLIS));
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 4, service,
+                TEST_TIMEOUT_MILLIS));
 
         // The second vibration should have recorded that the vibrators were turned on.
         verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong());
-
-        cancelVibrate(service);  // Clean up repeating effect.
     }
 
-    @FlakyTest
     @Test
     public void vibrate_withNewUnknownUsageVibrationAndNotRepeating_ignoreNewVibration()
             throws Exception {
         mockVibrators(1);
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect alarmEffect = VibrationEffect.createWaveform(
-                new long[]{10, 10_000}, new int[]{255, 0}, -1);
+                new long[]{10, 10_000}, new int[]{128, 255}, -1);
         vibrate(service, alarmEffect, ALARM_ATTRS);
 
-        // VibrationThread will start this vibration async, wait until it has started.
-        assertTrue(waitUntil(s -> !fakeVibrator.getAllEffectSegments().isEmpty(), service,
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service,
                 TEST_TIMEOUT_MILLIS));
 
         vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
@@ -1053,23 +1070,24 @@
         // The second vibration shouldn't have recorded that the vibrators were turned on.
         verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong());
         // The second vibration shouldn't have played any prebaked segment.
-        assertFalse(mVibratorProviders.get(1).getAllEffectSegments().stream()
+        assertFalse(fakeVibrator.getAllEffectSegments().stream()
                 .anyMatch(PrebakedSegment.class::isInstance));
-        cancelVibrate(service);  // Clean up long effect.
     }
 
     @Test
     public void vibrate_withOngoingHigherImportanceVibration_ignoresEffect() throws Exception {
         mockVibrators(1);
-        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect effect = VibrationEffect.createWaveform(
-                new long[]{10_000, 10_000}, new int[]{128, 255}, -1);
+                new long[]{10, 10_000}, new int[]{128, 255}, -1);
         vibrate(service, effect, ALARM_ATTRS);
 
-        // VibrationThread will start this vibration async, so wait before checking it started.
-        assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2,
                 service, TEST_TIMEOUT_MILLIS));
 
         vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
@@ -1078,26 +1096,27 @@
         // The second vibration shouldn't have recorded that the vibrators were turned on.
         verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong());
         // The second vibration shouldn't have played any prebaked segment.
-        assertFalse(mVibratorProviders.get(1).getAllEffectSegments().stream()
+        assertFalse(fakeVibrator.getAllEffectSegments().stream()
                 .anyMatch(PrebakedSegment.class::isInstance));
-        cancelVibrate(service);  // Clean up long effect.
     }
 
     @Test
     public void vibrate_withOngoingLowerImportanceVibration_cancelsOngoingEffect()
             throws Exception {
         mockVibrators(1);
-        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
-        mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect effect = VibrationEffect.createWaveform(
-                new long[]{10_000, 10_000}, new int[]{128, 255}, -1);
+                new long[]{10, 10_000}, new int[]{128, 255}, -1);
         vibrate(service, effect, HAPTIC_FEEDBACK_ATTRS);
 
-        // VibrationThread will start this vibration async, so wait before checking it started.
-        assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
-                service, TEST_TIMEOUT_MILLIS));
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service,
+                TEST_TIMEOUT_MILLIS));
 
         vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
                 RINGTONE_ATTRS);
@@ -1105,10 +1124,8 @@
         // The second vibration should have recorded that the vibrators were turned on.
         verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong());
         // One segment played is the prebaked CLICK from the second vibration.
-        assertEquals(1,
-                mVibratorProviders.get(1).getAllEffectSegments().stream()
-                        .filter(PrebakedSegment.class::isInstance)
-                        .count());
+        assertEquals(1, fakeVibrator.getAllEffectSegments().stream()
+                .filter(PrebakedSegment.class::isInstance).count());
     }
 
     @Test
@@ -1139,10 +1156,8 @@
         // The new vibration should have recorded that the vibrators were turned on.
         verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong());
         // One segment played is the prebaked CLICK from the new vibration.
-        assertEquals(1,
-                mVibratorProviders.get(1).getAllEffectSegments().stream()
-                        .filter(PrebakedSegment.class::isInstance)
-                        .count());
+        assertEquals(1, mVibratorProviders.get(1).getAllEffectSegments().stream()
+                .filter(PrebakedSegment.class::isInstance).count());
     }
 
     @Test
@@ -1153,8 +1168,9 @@
                 .build();
 
         mockVibrators(1);
-        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
-        mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect effect = VibrationEffect.createWaveform(
@@ -1173,7 +1189,7 @@
         verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong());
         // One step segment (with several amplitudes) and one click should have played. Notably
         // there is no primitive segment.
-        List<VibrationEffectSegment> played = mVibratorProviders.get(1).getAllEffectSegments();
+        List<VibrationEffectSegment> played = fakeVibrator.getAllEffectSegments();
         assertEquals(2, played.size());
         assertEquals(1, played.stream().filter(StepSegment.class::isInstance).count());
         assertEquals(1, played.stream().filter(PrebakedSegment.class::isInstance).count());
@@ -1182,8 +1198,9 @@
     @Test
     public void vibrate_withInputDevices_vibratesInputDevices() throws Exception {
         mockVibrators(1);
-        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
-        mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1});
         when(mIInputManagerMock.getVibratorIds(eq(1))).thenReturn(new int[]{1});
         when(mIInputManagerMock.getInputDevice(eq(1))).thenReturn(createInputDeviceWithVibrator(1));
@@ -1198,7 +1215,7 @@
         vibrateAndWaitUntilFinished(service, effect, ALARM_ATTRS);
 
         verify(mIInputManagerMock).vibrateCombined(eq(1), eq(effect), any());
-        assertTrue(mVibratorProviders.get(1).getAllEffectSegments().isEmpty());
+        assertTrue(fakeVibrator.getAllEffectSegments().isEmpty());
     }
 
     @Test
@@ -1497,8 +1514,6 @@
         // Alarm vibration will be scaled with SCALE_NONE.
         assertEquals(1f,
                 ((PrimitiveSegment) fakeVibrator.getAllEffectSegments().get(2)).getScale(), 1e-5);
-
-        cancelVibrate(service); // Clean up long-ish effect.
     }
 
     @Test
@@ -1533,8 +1548,6 @@
         assertEquals(1, fakeVibrator.getAllEffectSegments().size());
 
         assertEquals(defaultAmplitude / 255f, fakeVibrator.getAmplitudes().get(0), 1e-5);
-
-        cancelVibrate(service); // Clean up long-ish effect.
     }
 
     @Test
@@ -1570,7 +1583,6 @@
 
         // Vibration is not stopped nearly after updating service.
         assertFalse(waitUntil(s -> !s.isVibrating(1), service, 50));
-        cancelVibrate(service); // Clean up long effect.
     }
 
     @Test
@@ -1596,8 +1608,6 @@
                 HAPTIC_FEEDBACK_ATTRS);
         // Haptic feedback played normally when it's from the default device.
         assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
-
-        cancelVibrate(service);  // Clean up long-ish effect.
     }
 
     @Test
@@ -1854,9 +1864,7 @@
         assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel);
 
         // Vibration is not cancelled.
-        assertFalse(waitUntil(s -> !s.isVibrating(1), service, CLEANUP_TIMEOUT_MILLIS));
         assertEquals(Arrays.asList(false), mVibratorProviders.get(1).getExternalControlStates());
-        cancelVibrate(service);  // Clean up long effect.
     }
 
     @Test
@@ -1910,9 +1918,7 @@
         assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel);
 
         // Vibration is not cancelled.
-        assertFalse(waitUntil(s -> !s.isVibrating(1), service, CLEANUP_TIMEOUT_MILLIS));
         assertEquals(Arrays.asList(false), mVibratorProviders.get(1).getExternalControlStates());
-        cancelVibrate(service);  // Clean up long effect.
     }
 
     @Test
@@ -2520,7 +2526,7 @@
                 int constant, boolean always) throws InterruptedException {
         HalVibration vib =
                 service.performHapticFeedbackInternal(UID, Context.DEVICE_ID_DEFAULT, PACKAGE_NAME,
-                        constant, always, "some reason", service);
+                        constant, always, "some reason", service, false /* fromIme */);
         if (vib != null) {
             vib.waitForEnd();
         }
@@ -2536,29 +2542,29 @@
 
     private HalVibration vibrateAndWaitUntilFinished(VibratorManagerService service,
             CombinedVibration effect, VibrationAttributes attrs) throws InterruptedException {
-        HalVibration vib =
-                service.vibrateWithPermissionCheck(UID, Context.DEVICE_ID_DEFAULT, PACKAGE_NAME,
-                        effect, attrs, "some reason", service);
+        HalVibration vib = vibrate(service, effect, attrs);
         if (vib != null) {
             vib.waitForEnd();
         }
-
         return vib;
     }
 
-    private void vibrate(VibratorManagerService service, VibrationEffect effect,
+    private HalVibration vibrate(VibratorManagerService service, VibrationEffect effect,
             VibrationAttributes attrs) {
-        vibrate(service, CombinedVibration.createParallel(effect), attrs);
+        return vibrate(service, CombinedVibration.createParallel(effect), attrs);
     }
 
-    private void vibrate(VibratorManagerService service, CombinedVibration effect,
+    private HalVibration vibrate(VibratorManagerService service, CombinedVibration effect,
             VibrationAttributes attrs) {
-        vibrateWithDevice(service, Context.DEVICE_ID_DEFAULT, effect, attrs);
+        return vibrateWithDevice(service, Context.DEVICE_ID_DEFAULT, effect, attrs);
     }
 
-    private void vibrateWithDevice(VibratorManagerService service, int deviceId,
+    private HalVibration vibrateWithDevice(VibratorManagerService service, int deviceId,
             CombinedVibration effect, VibrationAttributes attrs) {
-        service.vibrate(UID, deviceId, PACKAGE_NAME, effect, attrs, "some reason", service);
+        HalVibration vib = service.vibrateWithPermissionCheck(UID, deviceId, PACKAGE_NAME, effect,
+                attrs, "some reason", service);
+        mPendingVibrations.add(vib);
+        return vib;
     }
 
     private boolean waitUntil(Predicate<VibratorManagerService> predicate,
diff --git a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java
index 3912206..0cd88ef 100644
--- a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java
+++ b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java
@@ -18,7 +18,10 @@
 
 import android.annotation.NonNull;
 import android.frameworks.vibrator.IVibratorController;
+import android.frameworks.vibrator.VibrationParam;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.os.VibrationAttributes;
 
@@ -28,17 +31,38 @@
  */
 public final class FakeVibratorController extends IVibratorController.Stub {
 
+    private final Handler mHandler;
+    private VibratorControlService mVibratorControlService;
+    private VibrationParam[] mRequestResult = new VibrationParam[0];
+
     public boolean isLinkedToDeath = false;
     public boolean didRequestVibrationParams = false;
     public int requestVibrationType = VibrationAttributes.USAGE_UNKNOWN;
     public long requestTimeoutInMillis = 0;
 
+    public FakeVibratorController(Looper looper) {
+        mHandler = new Handler(looper);
+    }
+
+    public void setVibratorControlService(VibratorControlService service) {
+        mVibratorControlService = service;
+    }
+
+    public void setRequestResult(VibrationParam... params) {
+        mRequestResult = params;
+    }
+
     @Override
-    public void requestVibrationParams(int vibrationType, long timeoutInMillis, IBinder iBinder)
+    public void requestVibrationParams(int vibrationType, long timeoutInMillis, IBinder token)
             throws RemoteException {
         didRequestVibrationParams = true;
         requestVibrationType = vibrationType;
         requestTimeoutInMillis = timeoutInMillis;
+        mHandler.post(() -> {
+            if (mVibratorControlService != null) {
+                mVibratorControlService.onRequestVibrationParamsComplete(token, mRequestResult);
+            }
+        });
     }
 
     @Override
diff --git a/services/tests/voiceinteractiontests/Android.bp b/services/tests/voiceinteractiontests/Android.bp
index 8a79fe4..8c70851 100644
--- a/services/tests/voiceinteractiontests/Android.bp
+++ b/services/tests/voiceinteractiontests/Android.bp
@@ -45,6 +45,7 @@
         "servicestests-utils-mockito-extended",
         "truth",
         "frameworks-base-testutils",
+        "androidx.test.rules",
     ],
 
     libs: [
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/SoundTriggerTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/SoundTriggerTest.java
index 35170b3..a9c517d 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/SoundTriggerTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/SoundTriggerTest.java
@@ -16,19 +16,20 @@
 
 package com.android.server.soundtrigger;
 
+import android.hardware.soundtrigger.SoundTrigger;
 import android.hardware.soundtrigger.SoundTrigger.ConfidenceLevel;
 import android.hardware.soundtrigger.SoundTrigger.Keyphrase;
 import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent;
 import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra;
 import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
 import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
-import android.hardware.soundtrigger.SoundTrigger;
 import android.media.AudioFormat;
+import android.os.Binder;
 import android.os.Parcel;
 import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.os.Binder;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
 
 import java.util.Arrays;
 import java.util.Locale;
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index e83f03d..b292294 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -22,16 +22,21 @@
 genrule {
     name: "wmtests.protologsrc",
     srcs: [
+        ":protolog-impl",
         ":protolog-groups",
         ":wmtests-sources",
     ],
     tools: ["protologtool"],
     cmd: "$(location protologtool) transform-protolog-calls " +
         "--protolog-class com.android.internal.protolog.common.ProtoLog " +
-        "--protolog-impl-class com.android.internal.protolog.ProtoLogImpl " +
-        "--protolog-cache-class 'com.android.server.wm.ProtoLogCache' " +
         "--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
         "--loggroups-jar $(location :protolog-groups) " +
+        // Used for the ProtoLogIntegrationTest, where don't test decoding or writing to file
+        // so the parameters below are irrelevant.
+        "--viewer-config-file-path /some/unused/file/path.pb " +
+        "--legacy-viewer-config-file-path /some/unused/file/path.json.gz " +
+        "--legacy-output-file-path /some/unused/file/path.winscope " +
+        // END of irrelevant params.
         "--output-srcjar $(out) " +
         "$(locations :wmtests-sources)",
     out: ["wmtests.protolog.srcjar"],
@@ -42,7 +47,7 @@
 
     // We only want this apk build for tests.
     srcs: [
-        ":wmtests.protologsrc",
+        ":wmtests-sources",
         "src/**/*.aidl",
     ],
 
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index ef19791..d6c5173 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -49,6 +49,8 @@
     <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION"/>
     <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
     <uses-permission android:name="android.permission.MONITOR_INPUT"/>
+    <uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS"/>
+    <uses-permission android:name="android.permission.MANAGE_DEFAULT_APPLICATIONS"/>
 
     <!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) -->
     <application android:debuggable="true"
diff --git a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
index e21388e..3c02eee 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
@@ -38,6 +38,7 @@
 import static android.view.KeyEvent.KEYCODE_U;
 import static android.view.KeyEvent.KEYCODE_Z;
 
+import android.app.role.RoleManager;
 import android.content.Intent;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
@@ -51,16 +52,19 @@
 @Presubmit
 @SmallTest
 public class ModifierShortcutTests extends ShortcutKeyTestBase {
-    private static final SparseArray<String> META_SHORTCUTS =  new SparseArray<>();
+    private static final SparseArray<String> INTENT_SHORTCUTS =  new SparseArray<>();
+    private static final SparseArray<String> ROLE_SHORTCUTS =  new SparseArray<>();
     static {
-        META_SHORTCUTS.append(KEYCODE_U, Intent.CATEGORY_APP_CALCULATOR);
-        META_SHORTCUTS.append(KEYCODE_B, Intent.CATEGORY_APP_BROWSER);
-        META_SHORTCUTS.append(KEYCODE_C, Intent.CATEGORY_APP_CONTACTS);
-        META_SHORTCUTS.append(KEYCODE_E, Intent.CATEGORY_APP_EMAIL);
-        META_SHORTCUTS.append(KEYCODE_K, Intent.CATEGORY_APP_CALENDAR);
-        META_SHORTCUTS.append(KEYCODE_M, Intent.CATEGORY_APP_MAPS);
-        META_SHORTCUTS.append(KEYCODE_P, Intent.CATEGORY_APP_MUSIC);
-        META_SHORTCUTS.append(KEYCODE_S, Intent.CATEGORY_APP_MESSAGING);
+        // These shortcuts should align with those defined in bookmarks.xml
+        INTENT_SHORTCUTS.append(KEYCODE_U, Intent.CATEGORY_APP_CALCULATOR);
+        INTENT_SHORTCUTS.append(KEYCODE_C, Intent.CATEGORY_APP_CONTACTS);
+        INTENT_SHORTCUTS.append(KEYCODE_E, Intent.CATEGORY_APP_EMAIL);
+        INTENT_SHORTCUTS.append(KEYCODE_K, Intent.CATEGORY_APP_CALENDAR);
+        INTENT_SHORTCUTS.append(KEYCODE_M, Intent.CATEGORY_APP_MAPS);
+        INTENT_SHORTCUTS.append(KEYCODE_P, Intent.CATEGORY_APP_MUSIC);
+
+        ROLE_SHORTCUTS.append(KEYCODE_B, RoleManager.ROLE_BROWSER);
+        ROLE_SHORTCUTS.append(KEYCODE_S, RoleManager.ROLE_SMS);
     }
     private static final int ANY_DISPLAY_ID = 123;
 
@@ -74,13 +78,21 @@
      */
     @Test
     public void testMetaShortcuts() {
-        for (int i = 0; i < META_SHORTCUTS.size(); i++) {
-            final int keyCode = META_SHORTCUTS.keyAt(i);
-            final String category = META_SHORTCUTS.valueAt(i);
+        for (int i = 0; i < INTENT_SHORTCUTS.size(); i++) {
+            final int keyCode = INTENT_SHORTCUTS.keyAt(i);
+            final String category = INTENT_SHORTCUTS.valueAt(i);
 
             sendKeyCombination(new int[]{KEYCODE_META_LEFT, keyCode}, 0);
             mPhoneWindowManager.assertLaunchCategory(category);
         }
+
+        for (int i = 0; i < ROLE_SHORTCUTS.size(); i++) {
+            final int keyCode = ROLE_SHORTCUTS.keyAt(i);
+            final String role = ROLE_SHORTCUTS.valueAt(i);
+
+            sendKeyCombination(new int[]{KEYCODE_META_LEFT, keyCode}, 0);
+            mPhoneWindowManager.assertLaunchRole(role);
+        }
     }
 
     /**
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 e904eae..0a29dfb 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java
@@ -145,7 +145,7 @@
                         KeyboardLogEvent.SYSTEM_MUTE, KeyEvent.KEYCODE_MUTE, 0},
                 {"Meta + Ctrl + DPAD_UP -> Split screen navigation",
                         new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_DPAD_UP},
-                        KeyboardLogEvent.SPLIT_SCREEN_NAVIGATION, KeyEvent.KEYCODE_DPAD_UP,
+                        KeyboardLogEvent.MULTI_WINDOW_NAVIGATION, KeyEvent.KEYCODE_DPAD_UP,
                         META_ON | CTRL_ON},
                 {"Meta + Ctrl + DPAD_LEFT -> Split screen navigation",
                         new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_DPAD_LEFT},
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 1a26c45..0776c51 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -60,6 +60,7 @@
 import android.app.IActivityManager;
 import android.app.NotificationManager;
 import android.app.SearchManager;
+import android.app.role.RoleManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -124,6 +125,8 @@
 class TestPhoneWindowManager {
     private static final long TEST_SINGLE_KEY_DELAY_MILLIS
             = SingleKeyGestureDetector.MULTI_PRESS_TIMEOUT + 1000L * HW_TIMEOUT_MULTIPLIER;
+    private static final String TEST_BROWSER_ROLE_PACKAGE_NAME = "com.browser";
+    private static final String TEST_SMS_ROLE_PACKAGE_NAME = "com.sms";
 
     private PhoneWindowManager mPhoneWindowManager;
     private Context mContext;
@@ -151,6 +154,7 @@
     @Mock private UserManagerInternal mUserManagerInternal;
     @Mock private AudioManagerInternal mAudioManagerInternal;
     @Mock private SearchManager mSearchManager;
+    @Mock private RoleManager mRoleManager;
 
     @Mock private Display mDisplay;
     @Mock private DisplayRotation mDisplayRotation;
@@ -180,6 +184,9 @@
     private boolean mIsTalkBackEnabled;
     private boolean mIsTalkBackShortcutGestureEnabled;
 
+    private Intent mBrowserIntent;
+    private Intent mSmsIntent;
+
     private int mKeyEventPolicyFlags = FLAG_INTERACTIVE;
 
     private class TestTalkbackShortcutController extends TalkbackShortcutController {
@@ -290,6 +297,7 @@
         doReturn(mSensorPrivacyManager).when(mContext).getSystemService(
                 eq(SensorPrivacyManager.class));
         doReturn(mSearchManager).when(mContext).getSystemService(eq(SearchManager.class));
+        doReturn(mRoleManager).when(mContext).getSystemService(eq(RoleManager.class));
         doReturn(false).when(mPackageManager).hasSystemFeature(any());
         try {
             doThrow(new PackageManager.NameNotFoundException("test")).when(mPackageManager)
@@ -360,6 +368,21 @@
         doReturn(interceptionInfo)
                 .when(mWindowManagerInternal).getKeyInterceptionInfoFromToken(any());
 
+        doReturn(true).when(mRoleManager).isRoleAvailable(eq(RoleManager.ROLE_BROWSER));
+        doReturn(true).when(mRoleManager).isRoleAvailable(eq(RoleManager.ROLE_SMS));
+        doReturn(TEST_BROWSER_ROLE_PACKAGE_NAME).when(mRoleManager).getDefaultApplication(
+                eq(RoleManager.ROLE_BROWSER));
+        doReturn(TEST_SMS_ROLE_PACKAGE_NAME).when(mRoleManager).getDefaultApplication(
+                eq(RoleManager.ROLE_SMS));
+        mBrowserIntent = new Intent(Intent.ACTION_MAIN);
+        mBrowserIntent.setPackage(TEST_BROWSER_ROLE_PACKAGE_NAME);
+        mSmsIntent = new Intent(Intent.ACTION_MAIN);
+        mSmsIntent.setPackage(TEST_SMS_ROLE_PACKAGE_NAME);
+        doReturn(mBrowserIntent).when(mPackageManager).getLaunchIntentForPackage(
+                eq(TEST_BROWSER_ROLE_PACKAGE_NAME));
+        doReturn(mSmsIntent).when(mPackageManager).getLaunchIntentForPackage(
+                eq(TEST_SMS_ROLE_PACKAGE_NAME));
+
         Mockito.reset(mContext);
     }
 
@@ -670,6 +693,29 @@
         Mockito.reset(mContext);
     }
 
+    void assertLaunchRole(String role) {
+        mTestLooper.dispatchAll();
+        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        try {
+            verify(mContext).startActivityAsUser(intentCaptor.capture(), any());
+            switch (role) {
+                case RoleManager.ROLE_BROWSER:
+                    Assert.assertEquals(intentCaptor.getValue(), mBrowserIntent);
+                    break;
+                case RoleManager.ROLE_SMS:
+                    Assert.assertEquals(intentCaptor.getValue(), mSmsIntent);
+                    break;
+                default:
+                    throw new AssertionError("Role " + role + " not supported in tests.");
+            }
+        } catch (Throwable t) {
+            throw new AssertionError("failed to assert " + role, t);
+        }
+        // Reset verifier for next call.
+        Mockito.reset(mContext);
+    }
+
+
     void assertShowRecentApps() {
         mTestLooper.dispatchAll();
         verify(mStatusBarManagerInternal).showRecentApps(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 67c528c..09e7b91 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -527,7 +527,8 @@
 
         // The configuration change is still sent to the activity, even if it doesn't relaunch.
         final ActivityConfigurationChangeItem expected =
-                ActivityConfigurationChangeItem.obtain(activity.token, newConfig);
+                ActivityConfigurationChangeItem.obtain(activity.token, newConfig,
+                        activity.getActivityWindowInfo());
         verify(mClientLifecycleManager).scheduleTransactionItem(
                 eq(activity.app.getThread()), eq(expected));
     }
@@ -599,7 +600,8 @@
         final Configuration currentConfig = activity.getConfiguration();
         assertEquals(expectedOrientation, currentConfig.orientation);
         final ActivityConfigurationChangeItem expected =
-                ActivityConfigurationChangeItem.obtain(activity.token, currentConfig);
+                ActivityConfigurationChangeItem.obtain(activity.token, currentConfig,
+                        activity.getActivityWindowInfo());
         verify(mClientLifecycleManager).scheduleTransactionItem(activity.app.getThread(), expected);
         verify(displayRotation).onSetRequestedOrientation();
     }
@@ -818,7 +820,7 @@
 
             final ActivityConfigurationChangeItem expected =
                     ActivityConfigurationChangeItem.obtain(activity.token,
-                            activity.getConfiguration());
+                            activity.getConfiguration(), activity.getActivityWindowInfo());
             verify(mClientLifecycleManager).scheduleTransactionItem(
                     activity.app.getThread(), expected);
         } finally {
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 6132ee3..173a1b6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -74,7 +74,6 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -86,9 +85,9 @@
 import static org.mockito.ArgumentMatchers.notNull;
 
 import android.app.ActivityOptions;
+import android.app.ActivityOptions.BackgroundActivityStartMode;
 import android.app.AppOpsManager;
 import android.app.BackgroundStartPrivileges;
-import android.app.ComponentOptions.BackgroundActivityStartMode;
 import android.app.IApplicationThread;
 import android.app.PictureInPictureParams;
 import android.content.ComponentName;
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 0c1fbf3..1a1fe95 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -94,6 +94,7 @@
     public void setUp() throws Exception {
         assumeFalse(WindowManagerService.sEnableShellTransitions);
         mAppTransitionController = new AppTransitionController(mWm, mDisplayContent);
+        mWm.mAnimator.ready();
     }
 
     @Test
@@ -855,7 +856,7 @@
 
         // Prepare and start transition.
         prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
-        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        waitUntilWindowAnimatorIdle();
 
         // Animation run by the remote handler.
         assertTrue(remoteAnimationRunner.isAnimationStarted());
@@ -886,7 +887,7 @@
         // Prepare and start transition.
         prepareAndTriggerAppTransition(openingActivity, closingActivity,
                 null /* changingTaskFragment */);
-        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        waitUntilWindowAnimatorIdle();
 
         // Animation is not run by the remote handler because the activity is filling the Task.
         assertFalse(remoteAnimationRunner.isAnimationStarted());
@@ -921,7 +922,7 @@
         // Prepare and start transition.
         prepareAndTriggerAppTransition(openingActivity, closingActivity,
                 null /* changingTaskFragment */);
-        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        waitUntilWindowAnimatorIdle();
 
         // Animation run by the remote handler.
         assertTrue(remoteAnimationRunner.isAnimationStarted());
@@ -946,7 +947,7 @@
 
         // Prepare and start transition.
         prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
-        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        waitUntilWindowAnimatorIdle();
 
         // Animation run by the remote handler.
         assertTrue(remoteAnimationRunner.isAnimationStarted());
@@ -973,7 +974,7 @@
 
         // Prepare and start transition.
         prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment1);
-        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        waitUntilWindowAnimatorIdle();
 
         // Animation run by the remote handler.
         assertTrue(remoteAnimationRunner.isAnimationStarted());
@@ -997,7 +998,7 @@
 
         // Prepare and start transition.
         prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
-        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        waitUntilWindowAnimatorIdle();
 
         // Animation not run by the remote handler.
         assertFalse(remoteAnimationRunner.isAnimationStarted());
@@ -1024,7 +1025,7 @@
 
         // Prepare and start transition.
         prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
-        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        waitUntilWindowAnimatorIdle();
 
         // Animation should not run by the remote handler when there are non-embedded activities of
         // different UID.
@@ -1051,7 +1052,7 @@
 
         // Prepare and start transition.
         prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
-        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        waitUntilWindowAnimatorIdle();
 
         // Animation should not run by the remote handler when there is wallpaper in the transition.
         assertFalse(remoteAnimationRunner.isAnimationStarted());
@@ -1085,7 +1086,7 @@
 
         // Prepare and start transition.
         prepareAndTriggerAppTransition(activity1, null /* closingActivity */, taskFragment);
-        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        waitUntilWindowAnimatorIdle();
 
         // The animation will be animated remotely by client and all activities are input disabled
         // for untrusted animation.
@@ -1136,7 +1137,7 @@
 
         // Prepare and start transition.
         prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
-        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        waitUntilWindowAnimatorIdle();
 
         // The animation will be animated remotely by client and all activities are input disabled
         // for untrusted animation.
@@ -1178,7 +1179,7 @@
 
         // Prepare and start transition.
         prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
-        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        waitUntilWindowAnimatorIdle();
 
         // The animation will be animated remotely by client, but input should not be dropped for
         // fully trusted.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
index dc4e47d..4060d40 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
@@ -20,21 +20,26 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.util.DisplayMetrics.DENSITY_DEFAULT;
 
+import static com.android.server.wm.DesktopModeLaunchParamsModifier.DESKTOP_MODE_INITIAL_BOUNDS_SCALE;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
+import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
 
+import android.graphics.Rect;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.server.wm.LaunchParamsController.LaunchParamsModifier.Result;
+import com.android.window.flags.Flags;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -69,11 +74,19 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+    public void testReturnsContinueIfDesktopWindowingIsDisabled() {
+        assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(null).calculate());
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     public void testReturnsSkipIfTaskIsNull() {
         assertEquals(RESULT_SKIP, new CalculateRequestBuilder().setTask(null).calculate());
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     public void testReturnsSkipIfNotBoundsPhase() {
         final Task task = new TaskBuilder(mSupervisor).build();
         assertEquals(RESULT_SKIP, new CalculateRequestBuilder().setTask(task).setPhase(
@@ -81,6 +94,7 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     public void testReturnsSkipIfTaskNotUsingActivityTypeStandardOrUndefined() {
         final Task task = new TaskBuilder(mSupervisor).setActivityType(
                 ACTIVITY_TYPE_ASSISTANT).build();
@@ -88,6 +102,7 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     public void testReturnsDoneIfTaskUsingActivityTypeStandard() {
         final Task task = new TaskBuilder(mSupervisor).setActivityType(
                 ACTIVITY_TYPE_STANDARD).build();
@@ -95,6 +110,7 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     public void testReturnsDoneIfTaskUsingActivityTypeUndefined() {
         final Task task = new TaskBuilder(mSupervisor).setActivityType(
                 ACTIVITY_TYPE_UNDEFINED).build();
@@ -102,6 +118,7 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     public void testReturnsSkipIfCurrentParamsHasBounds() {
         final Task task = new TaskBuilder(mSupervisor).setActivityType(
                 ACTIVITY_TYPE_STANDARD).build();
@@ -110,15 +127,22 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     public void testUsesDefaultBounds() {
         final Task task = new TaskBuilder(mSupervisor).setActivityType(
                 ACTIVITY_TYPE_STANDARD).build();
+        final int displayHeight = 1600;
+        final int displayWidth = 2560;
+        task.getDisplayArea().setBounds(new Rect(0, 0, displayWidth, displayHeight));
+        final int desiredWidth = (int) (displayWidth * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+        final int desiredHeight = (int) (displayHeight * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
         assertEquals(RESULT_DONE, new CalculateRequestBuilder().setTask(task).calculate());
-        assertEquals(dpiToPx(task, 840), mResult.mBounds.width());
-        assertEquals(dpiToPx(task, 630), mResult.mBounds.height());
+        assertEquals(desiredWidth, mResult.mBounds.width());
+        assertEquals(desiredHeight, mResult.mBounds.height());
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     public void testUsesDisplayAreaAndWindowingModeFromSource() {
         final Task task = new TaskBuilder(mSupervisor).setActivityType(
                 ACTIVITY_TYPE_STANDARD).build();
@@ -131,11 +155,6 @@
         assertEquals(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode);
     }
 
-    private int dpiToPx(Task task, int dpi) {
-        float density = (float) task.getConfiguration().densityDpi / DENSITY_DEFAULT;
-        return (int) (dpi * density + 0.5f);
-    }
-
     private class CalculateRequestBuilder {
         private Task mTask;
         private int mPhase = PHASE_BOUNDS;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 4c32a58..a0461a6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -42,6 +42,7 @@
 import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
@@ -541,7 +542,7 @@
     }
 
     @Test
-    public void testUnhandledDragListenerNotCalledForNormalDrags() throws RemoteException {
+    public void testUnhandledDragNotCalledForNormalDrags() throws RemoteException {
         assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
 
         final IGlobalDragListener listener = mock(IGlobalDragListener.class);
@@ -552,15 +553,16 @@
     }
 
     @Test
-    public void testUnhandledDragListenerReceivesUnhandledDropOverWindow() {
+    public void testUnhandledDragReceivesUnhandledDropOverWindow() {
         assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
 
         final IGlobalDragListener listener = mock(IGlobalDragListener.class);
         doReturn(mock(Binder.class)).when(listener).asBinder();
         mTarget.setGlobalDragListener(listener);
         final int invalidXY = 100_000;
-        startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> {
-            // Notify the unhandled drag listener
+        startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG,
+                ClipData.newPlainText("label", "Test"), () -> {
+            // Trigger an unhandled drop and verify the global drag listener was called
             mTarget.reportDropWindow(mWindow.mInputChannelToken, invalidXY, invalidXY);
             mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY);
             mTarget.reportDropResult(mWindow.mClient, false);
@@ -575,15 +577,16 @@
     }
 
     @Test
-    public void testUnhandledDragListenerReceivesUnhandledDropOverNoValidWindow() {
+    public void testUnhandledDragReceivesUnhandledDropOverNoValidWindow() {
         assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
 
         final IGlobalDragListener listener = mock(IGlobalDragListener.class);
         doReturn(mock(Binder.class)).when(listener).asBinder();
         mTarget.setGlobalDragListener(listener);
         final int invalidXY = 100_000;
-        startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> {
-            // Notify the unhandled drag listener
+        startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG,
+                ClipData.newPlainText("label", "Test"), () -> {
+            // Trigger an unhandled drop and verify the global drag listener was called
             mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY);
             mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY);
             mTarget.onUnhandledDropCallback(true);
@@ -597,15 +600,38 @@
     }
 
     @Test
-    public void testUnhandledDragListenerCallbackTimeout() {
+    public void testUnhandledDragDoesNotReceiveUnhandledDropWithoutDragFlag() {
         assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
 
         final IGlobalDragListener listener = mock(IGlobalDragListener.class);
         doReturn(mock(Binder.class)).when(listener).asBinder();
         mTarget.setGlobalDragListener(listener);
         final int invalidXY = 100_000;
-        startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> {
-            // Notify the unhandled drag listener
+        startDrag(View.DRAG_FLAG_GLOBAL,
+                ClipData.newPlainText("label", "Test"), () -> {
+                    // Trigger an unhandled drop and verify the global drag listener was not called
+                    mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY);
+                    mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY);
+                    mToken = null;
+                    try {
+                        verify(listener, never()).onUnhandledDrop(any(), any());
+                    } catch (RemoteException e) {
+                        fail("Failed to verify unhandled drop: " + e);
+                    }
+                });
+    }
+
+    @Test
+    public void testUnhandledDragCallbackTimeout() {
+        assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
+
+        final IGlobalDragListener listener = mock(IGlobalDragListener.class);
+        doReturn(mock(Binder.class)).when(listener).asBinder();
+        mTarget.setGlobalDragListener(listener);
+        final int invalidXY = 100_000;
+        startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG,
+                ClipData.newPlainText("label", "Test"), () -> {
+            // Trigger an unhandled drop and verify the global drag listener was called
             mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY);
             mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
index 20bb549..faa6d97 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
@@ -27,6 +27,7 @@
 import android.graphics.PixelFormat;
 import android.platform.test.annotations.Presubmit;
 import android.view.InsetsSource;
+import android.view.inputmethod.ImeTracker;
 
 import androidx.test.filters.SmallTest;
 
@@ -34,6 +35,12 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+/**
+ * Tests for the {@link ImeInsetsSourceProvider} class.
+ *
+ * <p> Build/Install/Run:
+ * atest WmTests:ImeInsetsSourceProviderTest
+ */
 @SmallTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
@@ -56,7 +63,7 @@
         mDisplayContent.setImeControlTarget(popup);
         mDisplayContent.setImeLayeringTarget(appWin);
         popup.mAttrs.format = PixelFormat.TRANSPARENT;
-        mImeProvider.scheduleShowImePostLayout(appWin, null /* statsToken */);
+        mImeProvider.scheduleShowImePostLayout(appWin, ImeTracker.Token.empty());
         assertTrue(mImeProvider.isReadyToShowIme());
     }
 
@@ -65,7 +72,7 @@
         WindowState target = createWindow(null, TYPE_APPLICATION, "app");
         mDisplayContent.setImeLayeringTarget(target);
         mDisplayContent.updateImeInputAndControlTarget(target);
-        mImeProvider.scheduleShowImePostLayout(target, null /* statsToken */);
+        mImeProvider.scheduleShowImePostLayout(target, ImeTracker.Token.empty());
         assertTrue(mImeProvider.isReadyToShowIme());
     }
 
@@ -79,7 +86,7 @@
         mDisplayContent.setImeLayeringTarget(target);
         mDisplayContent.setImeControlTarget(target);
 
-        mImeProvider.scheduleShowImePostLayout(target, null /* statsToken */);
+        mImeProvider.scheduleShowImePostLayout(target, ImeTracker.Token.empty());
         assertFalse(mImeProvider.isImeShowing());
         mImeProvider.checkShowImePostLayout();
         assertTrue(mImeProvider.isImeShowing());
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 2085d61..1f15ec3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -371,6 +371,7 @@
         mDisplayContent.getInsetsPolicy().updateBarControlTarget(app);
         mDisplayContent.getInsetsPolicy().showTransient(statusBars(),
                 true /* isGestureOnSystemBar */);
+        mWm.mAnimator.ready();
         waitUntilWindowAnimatorIdle();
 
         assertTrue(mDisplayContent.getInsetsPolicy().isTransient(statusBars()));
diff --git a/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java b/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java
index af0d32c..c5bf78b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java
@@ -27,6 +27,8 @@
 
 import com.android.internal.protolog.ProtoLogGroup;
 import com.android.internal.protolog.ProtoLogImpl;
+import com.android.internal.protolog.common.IProtoLog;
+import com.android.internal.protolog.common.LogLevel;
 import com.android.internal.protolog.common.ProtoLog;
 
 import org.junit.After;
@@ -47,9 +49,9 @@
     @Ignore("b/163095037")
     @Test
     public void testProtoLogToolIntegration() {
-        ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+        IProtoLog mockedProtoLog = mock(IProtoLog.class);
         runWith(mockedProtoLog, this::testProtoLog);
-        verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.ERROR), eq(ProtoLogGroup.TEST_GROUP),
+        verify(mockedProtoLog).log(eq(LogLevel.ERROR), eq(ProtoLogGroup.TEST_GROUP),
                 anyInt(), eq(0b0010010111),
                 eq(com.android.internal.protolog.ProtoLogGroup.TEST_GROUP.isLogToLogcat()
                         ? "Test completed successfully: %b %d %x %f %% %s"
@@ -66,18 +68,13 @@
     /**
      * Starts protolog for the duration of {@code runnable}, with a ProtoLogImpl instance installed.
      */
-    private void runWith(ProtoLogImpl mockInstance, Runnable runnable) {
-        ProtoLogImpl original = ProtoLogImpl.getSingleInstance();
-        original.startProtoLog(null);
+    private void runWith(IProtoLog mockInstance, Runnable runnable) {
+        IProtoLog original = ProtoLog.getSingleInstance();
+        ProtoLogImpl.setSingleInstance(mockInstance);
         try {
-            ProtoLogImpl.setSingleInstance(mockInstance);
-            try {
-                runnable.run();
-            } finally {
-                ProtoLogImpl.setSingleInstance(original);
-            }
+            runnable.run();
         } finally {
-            original.stopProtoLog(null, false);
+            ProtoLogImpl.setSingleInstance(original);
         }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 9930c88..f7c253d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -46,7 +46,6 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
@@ -73,6 +72,7 @@
 import android.os.UserManager;
 import android.platform.test.annotations.Presubmit;
 import android.util.ArraySet;
+import android.util.IntArray;
 import android.util.SparseBooleanArray;
 import android.view.Surface;
 import android.window.TaskSnapshot;
@@ -527,20 +527,20 @@
         mTaskPersister.mUserTaskIdsOverride.put(1, true);
         mTaskPersister.mUserTaskIdsOverride.put(2, true);
         mTaskPersister.mUserTasksOverride = new ArrayList<>();
-        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask1").build());
-        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask2").build());
+        mTaskPersister.mUserTasksOverride.add(mTasks.get(0));
+        mTaskPersister.mUserTasksOverride.add(mTasks.get(1));
 
         // Assert no user tasks are initially loaded
         assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).hasLength(0);
 
         // Load user 0 tasks
-        mRecentTasks.loadUserRecentsLocked(TEST_USER_0_ID);
+        mRecentTasks.loadRecentTasksIfNeeded(TEST_USER_0_ID);
         assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID);
         assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID));
         assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID));
 
         // Load user 1 tasks
-        mRecentTasks.loadUserRecentsLocked(TEST_USER_1_ID);
+        mRecentTasks.loadRecentTasksIfNeeded(TEST_USER_1_ID);
         assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID);
         assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_1_ID);
         assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID));
@@ -575,15 +575,15 @@
         mTaskPersister.mUserTaskIdsOverride.put(2, true);
         mTaskPersister.mUserTaskIdsOverride.put(3, true);
         mTaskPersister.mUserTasksOverride = new ArrayList<>();
-        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask1").build());
-        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask2").build());
-        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask3").build());
+        mTaskPersister.mUserTasksOverride.add(mTasks.get(0));
+        mTaskPersister.mUserTasksOverride.add(mTasks.get(1));
+        mTaskPersister.mUserTasksOverride.add(mTasks.get(2));
 
         // Assert no user tasks are initially loaded
         assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).hasLength(0);
 
         // Load tasks
-        mRecentTasks.loadUserRecentsLocked(TEST_USER_0_ID);
+        mRecentTasks.loadRecentTasksIfNeeded(TEST_USER_0_ID);
         assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID);
 
         // Sort the time descendingly so the order should be in-sync with task recency (most
@@ -1419,8 +1419,6 @@
     }
 
     private List<RecentTaskInfo> getRecentTasks(int flags) {
-        doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
-        doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
         return mRecentTasks.getRecentTasks(MAX_VALUE, flags, true /* getTasksAllowed */,
                 TEST_USER_0_ID, 0 /* callingUid */).getList();
     }
@@ -1590,19 +1588,20 @@
         }
 
         @Override
-        SparseBooleanArray loadPersistedTaskIdsForUser(int userId) {
+        SparseBooleanArray readPersistedTaskIdsFromFileForUser(int userId) {
             if (mUserTaskIdsOverride != null) {
                 return mUserTaskIdsOverride;
             }
-            return super.loadPersistedTaskIdsForUser(userId);
+            return super.readPersistedTaskIdsFromFileForUser(userId);
         }
 
         @Override
-        List<Task> restoreTasksForUserLocked(int userId, SparseBooleanArray preaddedTasks) {
+        ArrayList<Task> restoreTasksForUserLocked(int userId, RecentTaskFiles recentTaskFiles,
+                IntArray existedTaskIds) {
             if (mUserTasksOverride != null) {
                 return mUserTasksOverride;
             }
-            return super.restoreTasksForUserLocked(userId, preaddedTasks);
+            return super.restoreTasksForUserLocked(userId, recentTaskFiles, existedTaskIds);
         }
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 11d9629..a163801 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -43,7 +43,6 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -113,6 +112,7 @@
         runWithScissors(mWm.mH, () -> mHandler = new TestHandler(null, mClock), 0);
         mController = new RemoteAnimationController(mWm, mDisplayContent, mAdapter,
                 mHandler, false /*isActivityEmbedding*/);
+        mWm.mAnimator.ready();
     }
 
     private WindowState createAppOverlayWindow() {
@@ -136,7 +136,7 @@
             adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
                     mFinishedCallback);
             mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
-            mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+            waitUntilWindowAnimatorIdle();
             final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
                     ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
             final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -168,7 +168,7 @@
             adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
                     mFinishedCallback);
             mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
-            mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+            waitUntilWindowAnimatorIdle();
             final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
                     ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
             final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -290,7 +290,7 @@
         adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
                 mFinishedCallback);
         mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
-        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        waitUntilWindowAnimatorIdle();
         final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
                 ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
         final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -336,7 +336,7 @@
         task.applyAnimationUnchecked(null /* lp */, true /* enter */, TRANSIT_OLD_TASK_OPEN,
                 false /* isVoiceInteraction */, null /* sources */);
         mController.goodToGo(TRANSIT_OLD_TASK_OPEN);
-        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        waitUntilWindowAnimatorIdle();
         final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
                 ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
         try {
@@ -363,7 +363,7 @@
             ((AnimationAdapter) record.mThumbnailAdapter).startAnimation(mMockThumbnailLeash,
                     mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION, mThumbnailFinishedCallback);
             mController.goodToGo(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE);
-            mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+            waitUntilWindowAnimatorIdle();
             final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
                     ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
             final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -417,7 +417,7 @@
             ((AnimationAdapter) record.mThumbnailAdapter).startAnimation(mMockThumbnailLeash,
                     mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION, mThumbnailFinishedCallback);
             mController.goodToGo(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE);
-            mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+            waitUntilWindowAnimatorIdle();
             final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
                     ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
             final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -471,7 +471,7 @@
             ((AnimationAdapter) record.mThumbnailAdapter).startAnimation(mMockThumbnailLeash,
                     mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION, mThumbnailFinishedCallback);
             mController.goodToGo(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE);
-            mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+            waitUntilWindowAnimatorIdle();
             final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
                     ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
             final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -526,7 +526,7 @@
             adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
                     mFinishedCallback);
             mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
-            mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+            waitUntilWindowAnimatorIdle();
             final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
                     ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
             final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -559,7 +559,7 @@
             adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
                     mFinishedCallback);
             mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
-            mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+            waitUntilWindowAnimatorIdle();
             final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
                     ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
             final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -595,7 +595,7 @@
             adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
                     mFinishedCallback);
             mController.goodToGo(TRANSIT_OLD_KEYGUARD_GOING_AWAY);
-            mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+            waitUntilWindowAnimatorIdle();
             final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
                     ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
             final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -645,7 +645,7 @@
             adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
                     mFinishedCallback);
             mController.goodToGo(TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER);
-            mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+            waitUntilWindowAnimatorIdle();
             final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
                     ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
             final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -782,7 +782,7 @@
 
             mDisplayContent.applySurfaceChangesTransaction();
             mController.goodToGo(TRANSIT_OLD_TASK_OPEN);
-            mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+            waitUntilWindowAnimatorIdle();
 
             verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_TASK_OPEN),
                     any(), any(), any(), any());
@@ -810,7 +810,7 @@
         adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
                 mFinishedCallback);
         mController.goodToGo(transit);
-        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        waitUntilWindowAnimatorIdle();
         return adapter;
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 6013063..da11e6a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -554,7 +554,7 @@
         mRootWindowContainer.applySleepTokens(true);
 
         // The display orientation should be changed by the activity so there is no relaunch.
-        verify(activity, never()).relaunchActivityLocked(anyBoolean());
+        verify(activity, never()).relaunchActivityLocked(anyBoolean(), anyInt());
         assertEquals(rotatedConfig.orientation, display.getConfiguration().orientation);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index a8f6fe8..7ab093d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -546,7 +546,7 @@
         // This makes sure all previous messages in the handler are fully processed vs. just popping
         // them from the message queue.
         final AtomicBoolean currentMessagesProcessed = new AtomicBoolean(false);
-        wm.mAnimator.getChoreographer().postFrameCallback(time -> {
+        wm.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
             synchronized (currentMessagesProcessed) {
                 currentMessagesProcessed.set(true);
                 currentMessagesProcessed.notifyAll();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
index 12ed3c2..319be89 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
@@ -29,8 +29,6 @@
 import android.platform.test.annotations.Presubmit;
 import android.util.SparseBooleanArray;
 
-import androidx.test.filters.FlakyTest;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -81,7 +79,7 @@
         }
         mTaskPersister.writePersistedTaskIdsForUser(taskIdsOnFile, mTestUserId);
         SparseBooleanArray newTaskIdsOnFile = mTaskPersister
-                .loadPersistedTaskIdsForUser(mTestUserId);
+                .readPersistedTaskIdsFromFileForUser(mTestUserId);
         assertEquals("TaskIds written differ from TaskIds read back from file",
                 taskIdsOnFile, newTaskIdsOnFile);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 7551b165..1233686 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -265,7 +265,7 @@
 
     @Override
     public boolean performHapticFeedback(int uid, String packageName, int effectId,
-            boolean always, String reason) {
+            boolean always, String reason, boolean fromIme) {
         return false;
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index a0e64bf..12f46df 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -82,7 +82,10 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
 import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.util.ArraySet;
 import android.util.MergedConfiguration;
 import android.view.ContentRecordingSession;
@@ -109,6 +112,7 @@
 import com.android.server.LocalServices;
 import com.android.server.wm.SensitiveContentPackages.PackageInfo;
 import com.android.server.wm.WindowManagerService.WindowContainerInfo;
+import com.android.window.flags.Flags;
 
 import com.google.common.truth.Expect;
 
@@ -140,6 +144,9 @@
     @Rule
     public Expect mExpect = Expect.create();
 
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
     @After
     public void tearDown() {
         mWm.mSensitiveContentPackages.clearBlockedApps();
@@ -1106,6 +1113,7 @@
                 argThat(h -> (h.inputConfig & InputConfig.SPY) == InputConfig.SPY));
     }
 
+    @RequiresFlagsDisabled(Flags.FLAG_MAGNIFICATION_ALWAYS_DRAW_FULLSCREEN_BORDER)
     @Test
     public void testDrawMagnifiedViewport() {
         final int displayId = mDisplayContent.mDisplayId;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index cd3ce91..c8ad4bd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -104,6 +104,7 @@
 import android.view.View;
 import android.view.WindowInsets;
 import android.view.WindowManager;
+import android.view.inputmethod.ImeTracker;
 import android.window.ClientWindowFrames;
 import android.window.ITaskFragmentOrganizer;
 import android.window.TaskFragmentOrganizer;
@@ -126,7 +127,7 @@
 /**
  * Tests for the {@link WindowState} class.
  *
- * Build/Install/Run:
+ * <p> Build/Install/Run:
  * atest WmTests:WindowStateTests
  */
 @SmallTest
@@ -1099,7 +1100,7 @@
         mDisplayContent.setImeInputTarget(app);
         app.setRequestedVisibleTypes(ime(), ime());
         assertTrue(mDisplayContent.shouldImeAttachedToApp());
-        controller.getImeSourceProvider().scheduleShowImePostLayout(app, null /* statsToken */);
+        controller.getImeSourceProvider().scheduleShowImePostLayout(app, ImeTracker.Token.empty());
         controller.getImeSourceProvider().getSource().setVisible(true);
         controller.updateAboveInsetsState(false);
 
@@ -1137,7 +1138,7 @@
         mDisplayContent.setImeInputTarget(app);
         app.setRequestedVisibleTypes(ime(), ime());
         assertTrue(mDisplayContent.shouldImeAttachedToApp());
-        controller.getImeSourceProvider().scheduleShowImePostLayout(app, null /* statsToken */);
+        controller.getImeSourceProvider().scheduleShowImePostLayout(app, ImeTracker.Token.empty());
         controller.getImeSourceProvider().getSource().setVisible(true);
         controller.updateAboveInsetsState(false);
 
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 44f4068..883c702 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -383,7 +383,7 @@
             return queryStatsForUid(volumeUuid, appInfo.uid, callingPackage);
         } else {
             // Multiple packages means we need to go manual
-            final int appId = UserHandle.getUserId(appInfo.uid);
+            final int appId = UserHandle.getAppId(appInfo.uid);
             final String[] packageNames = new String[] { packageName };
             final long[] ceDataInodes = new long[1];
             String[] codePaths = new String[0];
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 530a39e..2da352d 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -48,20 +48,25 @@
 import android.hardware.usb.UsbPortStatus;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Looper;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.service.usb.UsbServiceDumpProto;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.dump.DualDumpOutputStream;
+import com.android.internal.widget.LockPatternUtils;
 import com.android.server.FgThread;
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.SystemService;
@@ -147,6 +152,8 @@
     private final UsbSettingsManager mSettingsManager;
     private final UsbPermissionManager mPermissionManager;
 
+    static final int PACKAGE_MONITOR_OPERATION_ID = 1;
+    static final int STRONG_AUTH_OPERATION_ID = 2;
     /**
      * The user id of the current user. There might be several profiles (with separate user ids)
      * per user.
@@ -156,6 +163,10 @@
 
     private final Object mLock = new Object();
 
+    // Key: USB port id
+    // Value: A set of UIDs of requesters who request disabling usb data
+    private final ArrayMap<String, ArraySet<Integer>> mUsbDisableRequesters = new ArrayMap<>();
+
     /**
      * @return the {@link UsbUserSettingsManager} for the given userId
      */
@@ -261,6 +272,14 @@
         if (mDeviceManager != null) {
             mDeviceManager.bootCompleted();
         }
+        if (android.hardware.usb.flags.Flags.enableUsbDataSignalStaking()) {
+            new PackageUninstallMonitor()
+                    .register(mContext, UserHandle.ALL, BackgroundThread.getHandler());
+
+            new LockPatternUtils(mContext)
+                    .registerStrongAuthTracker(new StrongAuthTracker(mContext,
+                            BackgroundThread.getHandler().getLooper()));
+        }
     }
 
     /** Called when a user is unlocked. */
@@ -873,6 +892,11 @@
         Objects.requireNonNull(callback, "enableUsbData: callback must not be null. opId:"
                 + operationId);
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+
+        if (android.hardware.usb.flags.Flags.enableUsbDataSignalStaking()) {
+            if (!shouldUpdateUsbSignaling(portId, enable, Binder.getCallingUid())) return false;
+        }
+
         final long ident = Binder.clearCallingIdentity();
         boolean wait;
         try {
@@ -892,6 +916,31 @@
         return wait;
     }
 
+    /**
+     * If enable = true, exclude UID from update list.
+     * If enable = false, include UID in update list.
+     * Return false if enable = true and the list is empty (no updates).
+     * Return true otherwise (let downstream decide on updates).
+     */
+    private boolean shouldUpdateUsbSignaling(String portId, boolean enable, int uid) {
+        synchronized (mUsbDisableRequesters) {
+            if (!mUsbDisableRequesters.containsKey(portId)) {
+                mUsbDisableRequesters.put(portId, new ArraySet<>());
+            }
+
+            ArraySet<Integer> uidsOfDisableRequesters = mUsbDisableRequesters.get(portId);
+
+            if (enable) {
+                uidsOfDisableRequesters.remove(uid);
+                // re-enable USB port (return true) if there are no other disable requesters
+                return uidsOfDisableRequesters.isEmpty();
+            } else {
+                uidsOfDisableRequesters.add(uid);
+            }
+        }
+        return true;
+    }
+
     @Override
     public void enableUsbDataWhileDocked(String portId, int operationId,
             IUsbOperationInternal callback) {
@@ -1344,4 +1393,55 @@
     private static String removeLastChar(String value) {
         return value.substring(0, value.length() - 1);
     }
+
+    /**
+     * Upon app removal, clear associated UIDs from the mUsbDisableRequesters list
+     * and re-enable USB data signaling if no remaining apps require USB disabling.
+     */
+    private class PackageUninstallMonitor extends PackageMonitor {
+        @Override
+        public void onUidRemoved(int uid) {
+            synchronized (mUsbDisableRequesters) {
+                for (String portId : mUsbDisableRequesters.keySet()) {
+                    ArraySet<Integer> disabledUid = mUsbDisableRequesters.get(portId);
+                    if (disabledUid != null) {
+                        disabledUid.remove(uid);
+                        if (disabledUid.isEmpty()) {
+                            enableUsbData(portId, true, PACKAGE_MONITOR_OPERATION_ID,
+                                    new IUsbOperationInternal.Default());
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Implements a callback within StrongAuthTracker to disable USB data signaling
+     * when the device enters lockdown mode. This likely involves updating a state
+     * that controls USB data behavior.
+     */
+    private class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
+        private boolean mLockdownModeStatus;
+
+        StrongAuthTracker(Context context, Looper looper) {
+            super(context, looper);
+        }
+
+        @Override
+        public synchronized void onStrongAuthRequiredChanged(int userId) {
+
+            boolean lockDownTriggeredByUser = (getStrongAuthForUser(userId)
+                    & STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN) != 0;
+            //if it goes into the same lockdown status, no change is needed
+            if (mLockdownModeStatus == lockDownTriggeredByUser) {
+                return;
+            }
+            mLockdownModeStatus = lockDownTriggeredByUser;
+            for (UsbPort port: mPortManager.getPorts()) {
+                enableUsbData(port.getId(), !lockDownTriggeredByUser, STRONG_AUTH_OPERATION_ID,
+                        new IUsbOperationInternal.Default());
+            }
+        }
+    }
 }
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index b3db2de..862aff9 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -31,12 +31,11 @@
 import static android.provider.Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY;
 import static android.provider.Settings.Global.SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT;
 
-import static com.android.server.soundtrigger.SoundTriggerEvent.SessionEvent.Type;
-import static com.android.server.utils.EventLogger.Event.ALOGW;
-
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 import static com.android.server.soundtrigger.DeviceStateHandler.DeviceStateListener;
 import static com.android.server.soundtrigger.DeviceStateHandler.SoundTriggerDeviceState;
+import static com.android.server.soundtrigger.SoundTriggerEvent.SessionEvent.Type;
+import static com.android.server.utils.EventLogger.Event.ALOGW;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -94,8 +93,8 @@
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.SparseArray;
 import android.util.Slog;
+import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.ISoundTriggerService;
@@ -105,19 +104,17 @@
 import com.android.server.SystemService;
 import com.android.server.soundtrigger.SoundTriggerEvent.ServiceEvent;
 import com.android.server.soundtrigger.SoundTriggerEvent.SessionEvent;
-import com.android.server.utils.EventLogger.Event;
 import com.android.server.utils.EventLogger;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.function.Consumer;
-import java.util.List;
-import java.util.Set;
 import java.util.Deque;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.TreeMap;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
@@ -126,6 +123,7 @@
 import java.util.concurrent.LinkedBlockingDeque;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
 /**
@@ -257,6 +255,11 @@
         publishLocalService(SoundTriggerInternal.class, mLocalSoundTriggerService);
     }
 
+    private boolean hasCalling() {
+        return mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY_CALLING);
+    }
+
     @Override
     public void onBootPhase(int phase) {
         Slog.d(TAG, "onBootPhase: " + phase + " : " + isSafeMode());
@@ -282,11 +285,13 @@
             // Do so after registering the listener so we ensure that we don't drop any events
             mDeviceStateHandler.onPowerModeChanged(powerManager.getSoundTriggerPowerSaveMode());
 
-            // PhoneCallStateHandler initializes the original call state
-            mPhoneCallStateHandler = new PhoneCallStateHandler(
-                      mContext.getSystemService(SubscriptionManager.class),
-                      mContext.getSystemService(TelephonyManager.class),
-                      mDeviceStateHandler);
+            if (hasCalling()) {
+                // PhoneCallStateHandler initializes the original call state
+                mPhoneCallStateHandler = new PhoneCallStateHandler(
+                        mContext.getSystemService(SubscriptionManager.class),
+                        mContext.getSystemService(TelephonyManager.class),
+                        mDeviceStateHandler);
+            }
         }
         mMiddlewareService = ISoundTriggerMiddlewareService.Stub.asInterface(
                 ServiceManager.waitForService(Context.SOUND_TRIGGER_MIDDLEWARE_SERVICE));
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
index 0a1f3c7..ad7b9e6 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
@@ -411,7 +411,8 @@
                 audioFormat,
                 options,
                 callback,
-                /* shouldCloseAudioStreamWithDelayOnDetect= */ true);
+                /* shouldCloseAudioStreamWithDelayOnDetect= */ true,
+                /* shouldCheckPermissionsAndAppOpsOnDetected= */ true);
     }
 
     void startListeningFromWearableLocked(
@@ -481,12 +482,29 @@
                         return null;
                     }
                 };
+        /*
+         * By setting shouldCheckPermissionsAndAppOpsOnDetected to false, when the audio
+         * stream is sent from the sandboxed HotwordDetectionService to the non-sandboxed
+         * VoiceInteractionService as a result of second-stage hotword detection, audio-related
+         * permissions will not be checked against the VoiceInteractionService and the AppOpsManager
+         * will not be notified of the data flow to the VoiceInteractionService. These checks are
+         * not performed because the audio stream here originates from a remotely connected wearable
+         * device. It does not originate from the microphone of the device where this code runs on,
+         * or a microphone directly controlled by this system. Permission checks are expected to
+         * happen on the remote wearable device. From the perspective of this system, the audio
+         * stream is data received from an external source.
+         *
+         * Not notifying AppOpsManager allows this device's microphone indicator to remain off when
+         * this data flow happens. It avoids confusion since the audio does not originate from
+         * this device. The wearable is expected to turn on its own microphone indicator.
+         */
         handleExternalSourceHotwordDetectionLocked(
                 audioStream,
                 audioFormat,
                 options,
                 voiceInteractionCallback,
-                /* shouldCloseAudioStreamWithDelayOnDetect= */ false);
+                /* shouldCloseAudioStreamWithDelayOnDetect= */ false,
+                /* shouldCheckPermissionsAndAppOpsOnDetected= */ false);
     }
 
     @SuppressWarnings("GuardedBy")
@@ -495,7 +513,8 @@
             AudioFormat audioFormat,
             @Nullable PersistableBundle options,
             IMicrophoneHotwordDetectionVoiceInteractionCallback callback,
-            boolean shouldCloseAudioStreamWithDelayOnDetect) {
+            boolean shouldCloseAudioStreamWithDelayOnDetect,
+            boolean shouldCheckPermissionsAndAppOpsOnDetected) {
         if (DEBUG) {
             Slog.d(TAG, "#handleExternalSourceHotwordDetectionLocked");
         }
@@ -631,36 +650,39 @@
                                                     EXTERNAL_HOTWORD_CLEANUP_MILLIS,
                                                     TimeUnit.MILLISECONDS);
                                         }
-                                        try {
-                                            enforcePermissionsForDataDelivery();
-                                        } catch (SecurityException e) {
-                                            Slog.w(
-                                                    TAG,
-                                                    "Ignoring #onDetected due to a "
-                                                            + "SecurityException",
-                                                    e);
-                                            HotwordMetricsLogger.writeDetectorEvent(
-                                                    getDetectorType(),
-                                                    EXTERNAL_SOURCE_DETECT_SECURITY_EXCEPTION,
-                                                    mVoiceInteractionServiceUid);
+                                        if (shouldCheckPermissionsAndAppOpsOnDetected) {
                                             try {
-                                                callback.onHotwordDetectionServiceFailure(
+                                                enforcePermissionsForDataDelivery();
+                                            } catch (SecurityException e) {
+                                                Slog.w(
+                                                        TAG,
+                                                        "Ignoring #onDetected due to a "
+                                                                + "SecurityException",
+                                                        e);
+                                                HotwordMetricsLogger.writeDetectorEvent(
+                                                        getDetectorType(),
+                                                        EXTERNAL_SOURCE_DETECT_SECURITY_EXCEPTION,
+                                                        mVoiceInteractionServiceUid);
+                                                try {
+                                                    callback.onHotwordDetectionServiceFailure(
                                                         new HotwordDetectionServiceFailure(
                                                                 ONDETECTED_GOT_SECURITY_EXCEPTION,
                                                                 "Security exception occurs in "
                                                                         + "#onDetected method"));
-                                            } catch (RemoteException e1) {
-                                                notifyOnDetectorRemoteException();
-                                                throw e1;
+                                                } catch (RemoteException e1) {
+                                                    notifyOnDetectorRemoteException();
+                                                    throw e1;
+                                                }
+                                                return;
                                             }
-                                            return;
                                         }
                                         HotwordDetectedResult newResult;
                                         try {
                                             newResult =
-                                                    mHotwordAudioStreamCopier
-                                                            .startCopyingAudioStreams(
-                                                                    triggerResult);
+                                                mHotwordAudioStreamCopier
+                                                    .startCopyingAudioStreams(
+                                                        triggerResult,
+                                                        shouldCheckPermissionsAndAppOpsOnDetected);
                                         } catch (IOException e) {
                                             Slog.w(
                                                     TAG,
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java
index 65c95d1..6f00dc8 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java
@@ -87,19 +87,32 @@
     }
 
     /**
-     * Starts copying the audio streams in the given {@link HotwordDetectedResult}.
-     * <p>
-     * The returned {@link HotwordDetectedResult} is identical the one that was passed in, except
-     * that the {@link ParcelFileDescriptor}s within {@link HotwordDetectedResult#getAudioStreams()}
-     * are replaced with descriptors from pipes managed by {@link HotwordAudioStreamCopier}. The
-     * returned value should be passed on to the client (i.e., the voice interactor).
-     * </p>
-     *
-     * @throws IOException If there was an error creating the managed pipe.
+     * Calls {@link #startCopyingAudioStreams(HotwordDetectedResult, boolean)} and notifies
+     * AppOpsManager of the {@link AppOpsManager#OPSTR_RECORD_AUDIO_HOTWORD} operation.
      */
     @NonNull
     public HotwordDetectedResult startCopyingAudioStreams(@NonNull HotwordDetectedResult result)
             throws IOException {
+        return startCopyingAudioStreams(result, /* shouldNotifyAppOpsManager= */ true);
+    }
+
+    /**
+     * Starts copying the audio streams in the given {@link HotwordDetectedResult}.
+     *
+     * <p>The returned {@link HotwordDetectedResult} is identical the one that was passed in, except
+     * that the {@link ParcelFileDescriptor}s within {@link HotwordDetectedResult#getAudioStreams()}
+     * are replaced with descriptors from pipes managed by {@link HotwordAudioStreamCopier}. The
+     * returned value should be passed on to the client (i.e., the voice interactor).
+     *
+     * @param result The {@link HotwordDetectedResult} to copy from.
+     * @param shouldNotifyAppOpsManager Whether the {@link AppOpsManager} should be notified of the
+     *     {@link AppOpsManager#OPSTR_RECORD_AUDIO_HOTWORD} operation during the copy.
+     * @throws IOException If there was an error creating the managed pipe.
+     */
+    @NonNull
+    public HotwordDetectedResult startCopyingAudioStreams(
+            @NonNull HotwordDetectedResult result, boolean shouldNotifyAppOpsManager)
+            throws IOException {
         List<HotwordAudioStream> audioStreams = result.getAudioStreams();
         if (audioStreams.isEmpty()) {
             HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
@@ -154,8 +167,12 @@
 
         String resultTaskId = TASK_ID_PREFIX + System.identityHashCode(result);
         mExecutorService.execute(
-                new HotwordDetectedResultCopyTask(resultTaskId, copyTaskInfos,
-                        totalMetadataBundleSizeBytes, totalInitialAudioSizeBytes));
+                new HotwordDetectedResultCopyTask(
+                        resultTaskId,
+                        copyTaskInfos,
+                        totalMetadataBundleSizeBytes,
+                        totalInitialAudioSizeBytes,
+                        shouldNotifyAppOpsManager));
 
         return result.buildUpon().setAudioStreams(newAudioStreams).build();
     }
@@ -178,13 +195,19 @@
         private final int mTotalMetadataSizeBytes;
         private final int mTotalInitialAudioSizeBytes;
         private final ExecutorService mExecutorService = Executors.newCachedThreadPool();
+        private final boolean mShouldNotifyAppOpsManager;
 
-        HotwordDetectedResultCopyTask(String resultTaskId, List<CopyTaskInfo> copyTaskInfos,
-                int totalMetadataSizeBytes, int totalInitialAudioSizeBytes) {
+        HotwordDetectedResultCopyTask(
+                String resultTaskId,
+                List<CopyTaskInfo> copyTaskInfos,
+                int totalMetadataSizeBytes,
+                int totalInitialAudioSizeBytes,
+                boolean shouldNotifyAppOpsManager) {
             mResultTaskId = resultTaskId;
             mCopyTaskInfos = copyTaskInfos;
             mTotalMetadataSizeBytes = totalMetadataSizeBytes;
             mTotalInitialAudioSizeBytes = totalInitialAudioSizeBytes;
+            mShouldNotifyAppOpsManager = shouldNotifyAppOpsManager;
         }
 
         @Override
@@ -200,55 +223,14 @@
                         mVoiceInteractorUid));
             }
 
-            if (mAppOpsManager.startOpNoThrow(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD,
-                    mVoiceInteractorUid, mVoiceInteractorPackageName,
-                    mVoiceInteractorAttributionTag, OP_MESSAGE) == MODE_ALLOWED) {
-                try {
-                    HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
-                            HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__STARTED,
-                            mVoiceInteractorUid, mTotalInitialAudioSizeBytes,
-                            mTotalMetadataSizeBytes, size);
-                    // TODO(b/244599891): Set timeout, close after inactivity
-                    mExecutorService.invokeAll(tasks);
-
-                    // We are including the non-streamed initial audio
-                    // (HotwordAudioStream.getInitialAudio()) bytes in the "stream" size metrics.
-                    int totalStreamSizeBytes = mTotalInitialAudioSizeBytes;
-                    for (SingleAudioStreamCopyTask task : tasks) {
-                        totalStreamSizeBytes += task.mTotalCopiedBytes;
-                    }
-
-                    Slog.i(TAG, mResultTaskId + ": Task was completed. Total bytes egressed: "
-                            + totalStreamSizeBytes + " (including " + mTotalInitialAudioSizeBytes
-                            + " bytes NOT streamed), total metadata bundle size bytes: "
-                            + mTotalMetadataSizeBytes);
-                    HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
-                            HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__ENDED,
-                            mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes,
-                            size);
-                } catch (InterruptedException e) {
-                    // We are including the non-streamed initial audio
-                    // (HotwordAudioStream.getInitialAudio()) bytes in the "stream" size metrics.
-                    int totalStreamSizeBytes = mTotalInitialAudioSizeBytes;
-                    for (SingleAudioStreamCopyTask task : tasks) {
-                        totalStreamSizeBytes += task.mTotalCopiedBytes;
-                    }
-
-                    HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
-                            HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__INTERRUPTED_EXCEPTION,
-                            mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes,
-                            size);
-                    Slog.i(TAG, mResultTaskId + ": Task was interrupted. Total bytes egressed: "
-                            + totalStreamSizeBytes + " (including " + mTotalInitialAudioSizeBytes
-                            + " bytes NOT streamed), total metadata bundle size bytes: "
-                            + mTotalMetadataSizeBytes);
-                    bestEffortPropagateError(e.getMessage());
-                } finally {
-                    mAppOpsManager.finishOp(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD,
-                            mVoiceInteractorUid, mVoiceInteractorPackageName,
-                            mVoiceInteractorAttributionTag);
-                }
-            } else {
+            if (mShouldNotifyAppOpsManager
+                    && mAppOpsManager.startOpNoThrow(
+                                    AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD,
+                                    mVoiceInteractorUid,
+                                    mVoiceInteractorPackageName,
+                                    mVoiceInteractorAttributionTag,
+                                    OP_MESSAGE)
+                            != MODE_ALLOWED) {
                 HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
                         HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__NO_PERMISSION,
                         mVoiceInteractorUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0,
@@ -258,6 +240,56 @@
                                 + " uid=" + mVoiceInteractorUid
                                 + " packageName=" + mVoiceInteractorPackageName
                                 + " attributionTag=" + mVoiceInteractorAttributionTag);
+                return;
+            }
+            try {
+                HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
+                        HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__STARTED,
+                        mVoiceInteractorUid, mTotalInitialAudioSizeBytes,
+                        mTotalMetadataSizeBytes, size);
+                // TODO(b/244599891): Set timeout, close after inactivity
+                mExecutorService.invokeAll(tasks);
+
+                // We are including the non-streamed initial audio
+                // (HotwordAudioStream.getInitialAudio()) bytes in the "stream" size metrics.
+                int totalStreamSizeBytes = mTotalInitialAudioSizeBytes;
+                for (SingleAudioStreamCopyTask task : tasks) {
+                    totalStreamSizeBytes += task.mTotalCopiedBytes;
+                }
+
+                Slog.i(TAG, mResultTaskId + ": Task was completed. Total bytes egressed: "
+                        + totalStreamSizeBytes + " (including " + mTotalInitialAudioSizeBytes
+                        + " bytes NOT streamed), total metadata bundle size bytes: "
+                        + mTotalMetadataSizeBytes);
+                HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
+                        HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__ENDED,
+                        mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes,
+                        size);
+            } catch (InterruptedException e) {
+                // We are including the non-streamed initial audio
+                // (HotwordAudioStream.getInitialAudio()) bytes in the "stream" size metrics.
+                int totalStreamSizeBytes = mTotalInitialAudioSizeBytes;
+                for (SingleAudioStreamCopyTask task : tasks) {
+                    totalStreamSizeBytes += task.mTotalCopiedBytes;
+                }
+
+                HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
+                        HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__INTERRUPTED_EXCEPTION,
+                        mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes,
+                        size);
+                Slog.i(TAG, mResultTaskId + ": Task was interrupted. Total bytes egressed: "
+                        + totalStreamSizeBytes + " (including " + mTotalInitialAudioSizeBytes
+                        + " bytes NOT streamed), total metadata bundle size bytes: "
+                        + mTotalMetadataSizeBytes);
+                bestEffortPropagateError(e.getMessage());
+            } finally {
+                if (mShouldNotifyAppOpsManager) {
+                    mAppOpsManager.finishOp(
+                            AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD,
+                            mVoiceInteractorUid,
+                            mVoiceInteractorPackageName,
+                            mVoiceInteractorAttributionTag);
+                }
             }
         }
 
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index c217780..5a52968 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -16,15 +16,21 @@
 
 package com.android.server.voiceinteraction;
 
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
+import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
 
 import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
 import android.app.AppGlobals;
+import android.app.admin.DevicePolicyManagerInternal;
 import android.app.role.OnRoleHoldersChangedListener;
 import android.app.role.RoleManager;
 import android.content.ComponentName;
@@ -41,6 +47,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.graphics.Bitmap;
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
 import android.hardware.soundtrigger.KeyphraseMetadata;
 import android.hardware.soundtrigger.ModelParams;
@@ -59,7 +66,6 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
-import android.os.PermissionEnforcer;
 import android.os.PersistableBundle;
 import android.os.RemoteCallback;
 import android.os.RemoteCallbackList;
@@ -69,7 +75,6 @@
 import android.os.ShellCallback;
 import android.os.Trace;
 import android.os.UserHandle;
-import android.permission.flags.Flags;
 import android.provider.Settings;
 import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
 import android.service.voice.IVisualQueryDetectionVoiceInteractionCallback;
@@ -84,6 +89,7 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
+import android.window.ScreenCapture;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -110,7 +116,9 @@
 import com.android.server.policy.AppOpsPolicy;
 import com.android.server.utils.Slogf;
 import com.android.server.utils.TimingsTraceAndSlog;
+import com.android.server.wm.ActivityAssistInfo;
 import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.WindowManagerInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -127,6 +135,19 @@
     static final String TAG = "VoiceInteractionManager";
     static final boolean DEBUG = false;
 
+    /** Static constants used by Contextual Search helper. */
+    private static final String CS_KEY_FLAG_SECURE_FOUND =
+            "com.android.contextualsearch.flag_secure_found";
+    private static final String CS_KEY_FLAG_SCREENSHOT =
+            "com.android.contextualsearch.screenshot";
+    private static final String CS_KEY_FLAG_IS_MANAGED_PROFILE_VISIBLE =
+            "com.android.contextualsearch.is_managed_profile_visible";
+    private static final String CS_KEY_FLAG_VISIBLE_PACKAGE_NAMES =
+            "com.android.contextualsearch.visible_package_names";
+    private static final String CS_INTENT_FILTER =
+            "com.android.contextualsearch.LAUNCH";
+
+
     final Context mContext;
     final ContentResolver mResolver;
     // Can be overridden for testing purposes
@@ -135,6 +156,8 @@
     final ActivityManagerInternal mAmInternal;
     final ActivityTaskManagerInternal mAtmInternal;
     final UserManagerInternal mUserManagerInternal;
+    final WindowManagerInternal mWmInternal;
+    final DevicePolicyManagerInternal mDpmInternal;
     final ArrayMap<Integer, VoiceInteractionManagerServiceStub.SoundTriggerSession>
             mLoadedKeyphraseIds = new ArrayMap<>();
     ShortcutServiceInternal mShortcutServiceInternal;
@@ -156,7 +179,8 @@
                 LocalServices.getService(ActivityManagerInternal.class));
         mAtmInternal = Objects.requireNonNull(
                 LocalServices.getService(ActivityTaskManagerInternal.class));
-
+        mWmInternal = LocalServices.getService(WindowManagerInternal.class);
+        mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
         LegacyPermissionManagerInternal permissionManagerInternal = LocalServices.getService(
                 LegacyPermissionManagerInternal.class);
         permissionManagerInternal.setVoiceInteractionPackagesProvider(
@@ -1019,6 +1043,56 @@
         public boolean showSessionFromSession(@NonNull IBinder token, @Nullable Bundle sessionArgs,
                 int flags, @Nullable String attributionTag) {
             synchronized (this) {
+                final String csKey = mContext.getResources()
+                        .getString(R.string.config_defaultContextualSearchKey);
+                final String csEnabledKey = mContext.getResources()
+                        .getString(R.string.config_defaultContextualSearchEnabled);
+
+                // If the request is for Contextual Search, process it differently
+                if (sessionArgs != null && sessionArgs.containsKey(csKey)) {
+                    if (sessionArgs.getBoolean(csEnabledKey, true)) {
+                        // If Contextual Search is enabled, try to follow that path.
+                        Intent launchIntent = getContextualSearchIntent(sessionArgs);
+                        if (launchIntent != null) {
+                            // Hand over to contextual search helper.
+                            Slog.d(TAG, "Handed over to contextual search helper.");
+                            final long caller = Binder.clearCallingIdentity();
+                            try {
+                                return startContextualSearch(launchIntent);
+                            } finally {
+                                Binder.restoreCallingIdentity(caller);
+                            }
+                        }
+                    }
+
+                    // Since we are here, Contextual Search helper couldn't handle the request.
+                    final String visEnabledKey = mContext.getResources()
+                            .getString(R.string.config_defaultContextualSearchLegacyEnabled);
+                    if (sessionArgs.getBoolean(visEnabledKey, true)) {
+                        // If visEnabledKey is set to true (or absent), we try following VIS path.
+                        String csPkgName = mContext.getResources()
+                                .getString(R.string.config_defaultContextualSearchPackageName);
+                        if (!csPkgName.equals(getCurInteractor(
+                                Binder.getCallingUserHandle().getIdentifier()).getPackageName())) {
+                            // Check if the interactor can handle Contextual Search.
+                            // If not, return failure.
+                            Slog.w(TAG, "Contextual Search not supported yet. Returning failure.");
+                            return false;
+                        }
+                    } else {
+                        // If visEnabledKey is set to false AND the request was for Contextual
+                        // Search, return false.
+                        return false;
+                    }
+                    // Given that we haven't returned yet, we can say that
+                    // - Contextual Search Helper couldn't handle the request
+                    // - VIS path for Contextual Search is enabled
+                    // - The current interactor supports Contextual Search.
+                    // Hence, we will proceed with the VIS path.
+                    Slog.d(TAG, "Contextual search not supported yet. Proceeding with VIS.");
+
+                }
+
                 if (mImpl == null) {
                     Slog.w(TAG, "showSessionFromSession without running voice interaction service");
                     return false;
@@ -1331,17 +1405,6 @@
             }
         }
 
-        // Enforce permissions that are flag controlled. The flag value decides if the permission
-        // should be enforced.
-        private void initAndVerifyDetector_enforcePermissionWithFlags() {
-            PermissionEnforcer enforcer = mContext.getSystemService(PermissionEnforcer.class);
-            if (Flags.voiceActivationPermissionApis()) {
-                enforcer.enforcePermission(
-                        android.Manifest.permission.RECEIVE_SANDBOX_TRIGGER_AUDIO,
-                        getCallingPid(), getCallingUid());
-            }
-        }
-
         @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION)
         @Override
         public void initAndVerifyDetector(
@@ -1351,13 +1414,7 @@
                 @NonNull IBinder token,
                 IHotwordRecognitionStatusCallback callback,
                 int detectorType) {
-            // TODO(b/305787465): Remove the MANAGE_HOTWORD_DETECTION permission enforcement on the
-            // {@link #initAndVerifyDetector(Identity,  PersistableBundle, ShareMemory, IBinder,
-            // IHotwordRecognitionStatusCallback, int)}
-            // and replace with the permission RECEIVE_SANDBOX_TRIGGER_AUDIO when it is fully
-            // launched.
             super.initAndVerifyDetector_enforcePermission();
-            initAndVerifyDetector_enforcePermissionWithFlags();
 
             synchronized (this) {
                 enforceIsCurrentVoiceInteractionService();
@@ -2644,6 +2701,76 @@
                 }
             }
         };
+
+        private Intent getContextualSearchIntent(Bundle args) {
+            String csPkgName = mContext.getResources()
+                    .getString(R.string.config_defaultContextualSearchPackageName);
+            if (csPkgName.isEmpty()) {
+                // Return null if csPackageName is not specified.
+                return null;
+            }
+            Intent launchIntent = new Intent(CS_INTENT_FILTER);
+            launchIntent.setPackage(csPkgName);
+            ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(
+                    launchIntent, PackageManager.MATCH_FACTORY_ONLY);
+            if (resolveInfo == null) {
+                return null;
+            }
+            launchIntent.setComponent(resolveInfo.getComponentInfo().getComponentName());
+            launchIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_ANIMATION
+                    | FLAG_ACTIVITY_NO_USER_ACTION);
+            launchIntent.putExtras(args);
+            boolean isAssistDataAllowed = mAtmInternal.isAssistDataAllowed();
+            final List<ActivityAssistInfo> records = mAtmInternal.getTopVisibleActivities();
+            ArrayList<String> visiblePackageNames = new ArrayList<>();
+            boolean isManagedProfileVisible = false;
+            for (ActivityAssistInfo record: records) {
+                // Add the package name to the list only if assist data is allowed.
+                if (isAssistDataAllowed) {
+                    visiblePackageNames.add(record.getComponentName().getPackageName());
+                }
+                if (mDpmInternal != null
+                        && mDpmInternal.isUserOrganizationManaged(record.getUserId())) {
+                    isManagedProfileVisible = true;
+                }
+            }
+            final ScreenCapture.ScreenshotHardwareBuffer shb;
+            if (mWmInternal != null) {
+                shb = mWmInternal.takeAssistScreenshot();
+            } else {
+                shb = null;
+            }
+            final Bitmap bm = shb != null ? shb.asBitmap() : null;
+            // Now that everything is fetched, putting it in the launchIntent.
+            if (bm != null) {
+                launchIntent.putExtra(CS_KEY_FLAG_SECURE_FOUND, shb.containsSecureLayers());
+                // Only put the screenshot if assist data is allowed
+                if (isAssistDataAllowed) {
+                    launchIntent.putExtra(CS_KEY_FLAG_SCREENSHOT, bm.asShared());
+                }
+            }
+            launchIntent.putExtra(CS_KEY_FLAG_IS_MANAGED_PROFILE_VISIBLE, isManagedProfileVisible);
+            // Only put the list of visible package names if assist data is allowed
+            if (isAssistDataAllowed) {
+                launchIntent.putExtra(CS_KEY_FLAG_VISIBLE_PACKAGE_NAMES, visiblePackageNames);
+            }
+
+            return launchIntent;
+        }
+
+        @RequiresPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS)
+        private boolean startContextualSearch(Intent launchIntent) {
+            // Contextual search starts with a frozen screen - so we launch without
+            // any system animations or starting window.
+            final ActivityOptions opts = ActivityOptions.makeCustomTaskAnimation(mContext,
+                    /* enterResId= */ 0, /* exitResId= */ 0, null, null, null);
+            opts.setDisableStartingWindow(true);
+            int resultCode = mAtmInternal.startActivityWithScreenshot(launchIntent,
+                    mContext.getPackageName(), Binder.getCallingUid(), Binder.getCallingPid(), null,
+                    opts.toBundle(), Binder.getCallingUserHandle().getIdentifier());
+            return resultCode == ActivityManager.START_SUCCESS;
+        }
+
     }
 
     /**
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 9792cdd..048b1b2 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1434,11 +1434,14 @@
     }
 
     /**
-     * This API will return all {@link PhoneAccount}s registered via
-     * {@link TelecomManager#registerPhoneAccount(PhoneAccount)}. If a {@link PhoneAccount} appears
-     * to be missing from the list, Telecom has either unregistered the {@link PhoneAccount}
-     * or the caller registered the {@link PhoneAccount} under a different user and does not
-     * have the {@link android.Manifest.permission#INTERACT_ACROSS_USERS} permission.
+     * This API will return all {@link PhoneAccount}s the caller registered via
+     * {@link TelecomManager#registerPhoneAccount(PhoneAccount)}.  If a {@link PhoneAccount} appears
+     * to be missing from the list, Telecom has either unregistered the {@link PhoneAccount} (for
+     * cleanup purposes) or the caller registered the {@link PhoneAccount} under a different user
+     * and does not have the  {@link android.Manifest.permission#INTERACT_ACROSS_USERS} permission.
+     * <b>Note:</b> This API will only return {@link PhoneAccount}s registered by the same app.  For
+     * system Dialers that need all the {@link PhoneAccount}s registered by every application, see
+     * {@link TelecomManager#getAllPhoneAccounts()}.
      *
      * @return all the {@link PhoneAccount}s registered by the caller.
      */
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 82ed340..58488d1 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -573,7 +573,7 @@
      * Returns the number of this subscription.
      *
      * Starting with API level 30, returns the number of this subscription if the calling app meets
-     * one of the following requirements:
+     * at least one of the following requirements:
      * <ul>
      *     <li>If the calling app's target SDK is API level 29 or lower and the app has been granted
      *     the READ_PHONE_STATE permission.
@@ -584,8 +584,8 @@
      *     <li>If the calling app is the default SMS role holder.
      * </ul>
      *
-     * @return the number of this subscription, or an empty string if one of these requirements is
-     * not met
+     * @return the number of this subscription, or an empty string if none of the requirements
+     * are met.
      * @deprecated use {@link SubscriptionManager#getPhoneNumber(int)} instead, which takes a
      *             {@link #getSubscriptionId() subscription ID}.
      */
diff --git a/telephony/java/android/telephony/TelephonyFrameworkInitializer.java b/telephony/java/android/telephony/TelephonyFrameworkInitializer.java
index c2f5b8f..901daf8 100644
--- a/telephony/java/android/telephony/TelephonyFrameworkInitializer.java
+++ b/telephony/java/android/telephony/TelephonyFrameworkInitializer.java
@@ -19,12 +19,14 @@
 import android.annotation.NonNull;
 import android.app.SystemServiceRegistry;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.TelephonyServiceManager;
 import android.telephony.euicc.EuiccCardManager;
 import android.telephony.euicc.EuiccManager;
 import android.telephony.ims.ImsManager;
 import android.telephony.satellite.SatelliteManager;
 
+import com.android.internal.telephony.flags.Flags;
 import com.android.internal.util.Preconditions;
 
 
@@ -55,6 +57,11 @@
         sTelephonyServiceManager = Preconditions.checkNotNull(telephonyServiceManager);
     }
 
+    private static boolean hasSystemFeature(Context context, String feature) {
+        if (!Flags.minimalTelephonyManagersConditionalOnFeatures()) return true;
+        return context.getPackageManager().hasSystemFeature(feature);
+    }
+
     /**
      * Called by {@link SystemServiceRegistry}'s static initializer and registers all telephony
      * services to {@link Context}, so that {@link Context#getSystemService} can return them.
@@ -76,33 +83,39 @@
         SystemServiceRegistry.registerContextAwareService(
                 Context.CARRIER_CONFIG_SERVICE,
                 CarrierConfigManager.class,
-                context -> new CarrierConfigManager(context)
+                context -> hasSystemFeature(context, PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
+                        ? new CarrierConfigManager(context) : null
         );
         SystemServiceRegistry.registerContextAwareService(
                 Context.EUICC_SERVICE,
                 EuiccManager.class,
-                context -> new EuiccManager(context)
+                context -> hasSystemFeature(context, PackageManager.FEATURE_TELEPHONY_EUICC)
+                        ? new EuiccManager(context) : null
         );
         SystemServiceRegistry.registerContextAwareService(
                 Context.EUICC_CARD_SERVICE,
                 EuiccCardManager.class,
-                context -> new EuiccCardManager(context)
+                context -> hasSystemFeature(context, PackageManager.FEATURE_TELEPHONY_EUICC)
+                        ? new EuiccCardManager(context) : null
         );
         SystemServiceRegistry.registerContextAwareService(
                 Context.TELEPHONY_IMS_SERVICE,
                 ImsManager.class,
-                context -> new ImsManager(context)
+                context -> hasSystemFeature(context, PackageManager.FEATURE_TELEPHONY_IMS)
+                        ? new ImsManager(context) : null
         );
         SystemServiceRegistry.registerContextAwareService(
                 Context.SMS_SERVICE,
                 SmsManager.class,
-                context -> SmsManager.getSmsManagerForContextAndSubscriptionId(context,
-                        SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)
+                context -> hasSystemFeature(context, PackageManager.FEATURE_TELEPHONY_MESSAGING)
+                        ? SmsManager.getSmsManagerForContextAndSubscriptionId(context,
+                                SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) : null
         );
         SystemServiceRegistry.registerContextAwareService(
                 Context.SATELLITE_SERVICE,
                 SatelliteManager.class,
-                context -> new SatelliteManager(context)
+                context -> hasSystemFeature(context, PackageManager.FEATURE_TELEPHONY_SATELLITE)
+                        ? new SatelliteManager(context) : null
         );
     }
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 626a2e5..88acbab 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -8435,7 +8435,7 @@
      * In addition to the {@link Manifest.permission#MODIFY_PHONE_STATE} permission, callers of this
      * API must also be listed in the device configuration as an authorized app in
      * {@code packages/services/Telephony/res/values/config.xml} under the
-     * {@code config_number_verification_package_name} key.
+     * {@code platform_number_verification_package} key.
      *
      * @hide
      * @param range The range of phone numbers the caller expects a phone call from.
@@ -15023,7 +15023,7 @@
     @FlaggedApi(android.permission.flags.Flags.FLAG_GET_EMERGENCY_ROLE_HOLDER_API_ENABLED)
     @NonNull
     @SystemApi
-    public String getEmergencyAssistancePackage() {
+    public String getEmergencyAssistancePackageName() {
         if (!isEmergencyAssistanceEnabled() || !isVoiceCapable()) {
             throw new IllegalStateException("isEmergencyAssistanceEnabled() is false or device"
                 + " not voice capable.");
@@ -18535,7 +18535,7 @@
      * @hide
      */
     @SystemApi
-    @FlaggedApi(com.android.server.telecom.flags.Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES)
+    @FlaggedApi(com.android.server.telecom.flags.Flags.FLAG_GET_LAST_KNOWN_CELL_IDENTITY)
     @RequiresPermission(allOf = {Manifest.permission.ACCESS_FINE_LOCATION,
             Manifest.permission.ACCESS_LAST_KNOWN_CELL_ID})
     public @Nullable CellIdentity getLastKnownCellIdentity() {
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 9789082..3f02ae9 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -549,13 +549,19 @@
         public static final int CAPABILITY_TYPE_SMS = 1 << 3;
 
         /**
-         * This MmTelFeature supports Call Composer (section 2.4 of RC.20)
+         * This MmTelFeature supports Call Composer (section 2.4 of RC.20). This is the superset
+         * Call Composer, meaning that all subset types of Call Composers must be enabled when this
+         * capability is enabled
          */
         public static final int CAPABILITY_TYPE_CALL_COMPOSER = 1 << 4;
 
 
         /**
-         * This MmTelFeature supports Business-only Call Composer
+         * This MmTelFeature supports Business-only Call Composer. This is a subset of
+         * {@code CAPABILITY_TYPE_CALL_COMPOSER} that only supports business related
+         * information for calling (e.g. information to signal if the call is a business call) in
+         * the SIP header.  When enabling {@code CAPABILITY_TYPE_CALL_COMPOSER}, the
+         * {@code CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY} capability must also be enabled.
          */
         @FlaggedApi(Flags.FLAG_BUSINESS_CALL_COMPOSER)
         public static final int CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY = 1 << 5;
diff --git a/test-runner/src/android/test/InstrumentationTestRunner.java b/test-runner/src/android/test/InstrumentationTestRunner.java
index 07e3f87..b2a8847 100644
--- a/test-runner/src/android/test/InstrumentationTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationTestRunner.java
@@ -16,9 +16,7 @@
 
 package android.test;
 
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import com.android.internal.util.Predicate;
+import static android.test.suitebuilder.TestPredicates.hasAnnotation;
 
 import android.app.Activity;
 import android.app.Instrumentation;
@@ -29,16 +27,11 @@
 import android.test.suitebuilder.TestPredicates;
 import android.test.suitebuilder.TestSuiteBuilder;
 import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.PrintStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
+import com.android.internal.util.Predicate;
 
 import junit.framework.AssertionFailedError;
 import junit.framework.Test;
@@ -49,7 +42,14 @@
 import junit.runner.BaseTestRunner;
 import junit.textui.ResultPrinter;
 
-import static android.test.suitebuilder.TestPredicates.hasAnnotation;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.PrintStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * An {@link Instrumentation} that runs various types of {@link junit.framework.TestCase}s against
diff --git a/test-runner/src/android/test/suitebuilder/TestPredicates.java b/test-runner/src/android/test/suitebuilder/TestPredicates.java
index 616d1a9..faf31fd 100644
--- a/test-runner/src/android/test/suitebuilder/TestPredicates.java
+++ b/test-runner/src/android/test/suitebuilder/TestPredicates.java
@@ -19,7 +19,9 @@
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.Smoke;
 import android.test.suitebuilder.annotation.Suppress;
+
 import com.android.internal.util.Predicate;
+
 import java.lang.annotation.Annotation;
 
 /**
diff --git a/test-runner/tests/src/android/test/AndroidTestRunnerTest.java b/test-runner/tests/src/android/test/AndroidTestRunnerTest.java
index 6723548..bd6c04bc 100644
--- a/test-runner/tests/src/android/test/AndroidTestRunnerTest.java
+++ b/test-runner/tests/src/android/test/AndroidTestRunnerTest.java
@@ -19,15 +19,15 @@
 import android.test.mock.MockContext;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import java.util.ArrayList;
-import junit.framework.TestCase;
 import junit.framework.AssertionFailedError;
 import junit.framework.Test;
-import junit.framework.TestSuite;
+import junit.framework.TestCase;
 import junit.framework.TestListener;
+import junit.framework.TestSuite;
 
-import java.util.List;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * Unit tests for {@link AndroidTestRunner}
diff --git a/tests/CoreTests/android/Android.bp b/tests/CoreTests/android/Android.bp
index e2f194b..97a6e5f 100644
--- a/tests/CoreTests/android/Android.bp
+++ b/tests/CoreTests/android/Android.bp
@@ -16,5 +16,8 @@
         "android.test.base.stubs",
     ],
     sdk_version: "current",
-    static_libs: ["junit"],
+    static_libs: [
+        "junit",
+        "androidx.test.rules",
+    ],
 }
diff --git a/tests/CoreTests/android/core/RequestAPITest.java b/tests/CoreTests/android/core/RequestAPITest.java
index 206f228..2d420d3 100644
--- a/tests/CoreTests/android/core/RequestAPITest.java
+++ b/tests/CoreTests/android/core/RequestAPITest.java
@@ -19,10 +19,11 @@
 import android.net.http.RequestHandle;
 import android.net.http.RequestQueue;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 import android.webkit.CookieSyncManager;
 
+import androidx.test.filters.Suppress;
+
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 import java.util.HashMap;
diff --git a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java
index 217659e..700856c 100644
--- a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java
+++ b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java
@@ -726,7 +726,7 @@
                                       .map(Object::toString)
                                       .collect(Collectors.joining(", ")));
             int initialNumEvents = mModeChangedEvents.size();
-            surface.setFrameRate(30.f, compatibility);
+            surface.setFrameRate(70.f, compatibility);
             verifyFrameRates(expectedFrameRates, surface);
             verifyModeSwitchesDontChangeResolution(initialNumEvents, mModeChangedEvents.size());
         });
@@ -824,7 +824,7 @@
         Display display = getDisplay();
         List<Float> expectedFrameRates = getRefreshRates(display.getMode(), display)
                                                  .stream()
-                                                 .filter(rate -> rate >= 30.f)
+                                                 .filter(rate -> rate >= 70.f)
                                                  .collect(Collectors.toList());
 
         assumeTrue("**** testSurfaceControlFrameRateCompatibility SKIPPED because no refresh rate "
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
index 6209a08..ad39fa9 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
@@ -17,8 +17,8 @@
 package com.android.server.wm.flicker.activityembedding
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
 import org.junit.Before
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
index 0c36c59..46ad77e 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.activityembedding.close
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.Rect
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
index 955e801..af4f7a7 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.activityembedding.layoutchange
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.Rect
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
index ce9c337..e511b72 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.activityembedding.open
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.Rect
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
index 59ff0c6..5009c7c 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.activityembedding.open
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
index 3657820..000b457 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.activityembedding.open
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
index 9f9fc23..4352177 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.activityembedding.open
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.Rect
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
index 30e833f..62cf6cd 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.activityembedding.open
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.Rect
-import android.tools.common.flicker.subject.region.RegionSubject
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.subject.region.RegionSubject
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
index c8cac8f..aa8b4ce 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
@@ -17,14 +17,14 @@
 package com.android.server.wm.flicker.activityembedding.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.Rect
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.component.ComponentNameMatcher.Companion.TRANSITION_SNAPSHOT
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.subject.layers.LayersTraceSubject
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.component.ComponentNameMatcher.Companion.TRANSITION_SNAPSHOT
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
@@ -176,9 +176,7 @@
                 val secondaryVisibleRegion =
                     it.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
                 if (secondaryVisibleRegion.region.isNotEmpty) {
-                    check { "left" }
-                        .that(secondaryVisibleRegion.region.bounds.left)
-                        .isGreater(0)
+                    check { "left" }.that(secondaryVisibleRegion.region.bounds.left).isGreater(0)
                 }
             }
         }
@@ -217,7 +215,7 @@
         flicker.assertLayers {
             visibleLayersShownMoreThanOneConsecutiveEntry(
                 LayersTraceSubject.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS +
-                        listOf(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+                    listOf(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
             )
         }
     }
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
index 0dce870..3d834c1 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.activityembedding.rotation
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt
index f6d51f9..511c948 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.activityembedding.rotation
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
 import com.android.server.wm.flicker.helpers.setRotation
 import org.junit.Test
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
index 6be78f8..65a23e8 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.activityembedding.rtl
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
index 576eec8..7298e5f 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
@@ -18,12 +18,12 @@
 
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import android.tools.common.datatypes.Rect
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index 64dd44d..e19e1ce 100644
--- a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -16,11 +16,11 @@
 
 package com.android.server.wm.flicker.close
 
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.annotation.FlickerServiceCompatible
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import org.junit.FixMethodOrder
 import org.junit.Test
diff --git a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index eb256b5..47ed642 100644
--- a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -16,11 +16,11 @@
 
 package com.android.server.wm.flicker.close
 
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.annotation.FlickerServiceCompatible
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import org.junit.FixMethodOrder
 import org.junit.Test
diff --git a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index ea025c7..65bc356 100644
--- a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.close
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.component.ComponentNameMatcher.Companion.LAUNCHER
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.component.ComponentNameMatcher.Companion.LAUNCHER
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
index 89ab41e..ffa90a3 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.launch
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.TwoActivitiesAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
index 413767c..8c285bd 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
@@ -16,9 +16,9 @@
 
 package com.android.server.wm.flicker.launch
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.launch.common.OpenAppFromIconTransition
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
index 4168bdc..57da05f 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.launch
 
 import android.tools.device.apphelpers.CameraAppHelper
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.server.wm.flicker.launch.common.OpenAppFromLauncherTransition
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
@@ -52,6 +52,7 @@
                 // Can't use TAPL due to Recents not showing in 3 Button Nav in full screen mode
                 device.pressHome()
                 tapl.getWorkspace()
+                wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
             }
             teardown { testApp.exit(wmHelper) }
             transitions { testApp.launchViaIntent(wmHelper) }
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
index 9c55c98..267f282 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
@@ -18,12 +18,12 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
+import android.tools.flicker.annotation.FlickerServiceCompatible
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.launch.common.OpenAppFromLauncherTransition
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
index fc6cdb1..83065de 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.launch
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.annotation.FlickerServiceCompatible
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.launch.common.OpenAppFromLauncherTransition
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
index de666dd..44ae27c 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
@@ -17,13 +17,13 @@
 package com.android.server.wm.flicker.launch
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.annotation.FlickerServiceCompatible
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index f8a9961..6d3eaeb 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.launch
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.annotation.FlickerServiceCompatible
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.launch.common.OpenAppFromLauncherTransition
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
index 0aceb35..bec02d0 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
@@ -18,15 +18,15 @@
 
 import android.os.SystemClock
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.CameraAppHelper
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.rules.RemoveAllTasksButHomeRule
+import android.tools.flicker.subject.layers.LayersTraceSubject
+import android.tools.traces.component.ComponentNameMatcher
 import android.view.KeyEvent
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.setRotation
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
index f41a2a2..e0aef8d 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.launch
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.TransferSplashscreenAppHelper
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
index 93ca41c..f114499 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
@@ -20,15 +20,15 @@
 import android.os.Bundle
 import android.os.Handler
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.ConditionsFactory
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerBuilderProvider
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
+import android.tools.flicker.junit.FlickerBuilderProvider
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.rules.RemoveAllTasksButHomeRule
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.ConditionsFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
index 3aee932..b1d78cb 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -20,20 +20,20 @@
 import android.app.WallpaperManager
 import android.content.res.Resources
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.Region
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.common.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.component.ComponentNameMatcher.Companion.SPLASH_SCREEN
-import android.tools.common.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER
-import android.tools.common.traces.component.ComponentSplashScreenMatcher
-import android.tools.common.traces.component.IComponentMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.datatypes.Region
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.subject.layers.LayersTraceSubject
+import android.tools.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS
+import android.tools.helpers.WindowUtils
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.component.ComponentNameMatcher.Companion.SPLASH_SCREEN
+import android.tools.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER
+import android.tools.traces.component.ComponentSplashScreenMatcher
+import android.tools.traces.component.IComponentMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.BaseTest
@@ -215,9 +215,10 @@
             component: IComponentMatcher,
             expectedArea: Region,
             isOptional: Boolean = true
-        ): LayersTraceSubject = invoke("$component coversExactly $expectedArea", isOptional) {
-            it.visibleRegion(component).coversExactly(expectedArea)
-        }
+        ): LayersTraceSubject =
+            invoke("$component coversExactly $expectedArea", isOptional) {
+                it.visibleRegion(component).coversExactly(expectedArea)
+            }
 
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
index 802c755..8a3304b 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
@@ -16,10 +16,10 @@
 
 package com.android.server.wm.flicker.launch.common
 
-import android.tools.common.Rotation
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
+import android.tools.Rotation
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.rules.RemoveAllTasksButHomeRule
 
 abstract class OpenAppFromIconTransition(flicker: LegacyFlickerTest) :
     OpenAppFromLauncherTransition(flicker) {
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt
index 9d7096e..b56e9a5 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt
@@ -17,8 +17,8 @@
 package com.android.server.wm.flicker.launch.common
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.replacesLayer
 import org.junit.Test
 
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt
index 7b08843..f8fd3586 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.launch.common
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.navBarLayerPositionAtEnd
 import com.android.server.wm.flicker.statusBarLayerPositionAtEnd
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt
index 989619e..7ca336d 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.launch.common
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/Utils.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/Utils.kt
index 8242e9a..8a241de 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/Utils.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/Utils.kt
@@ -20,12 +20,12 @@
 import android.platform.test.rule.NavigationModeRule
 import android.platform.test.rule.PressHomeRule
 import android.platform.test.rule.UnlockScreenRule
-import android.tools.common.NavBar
-import android.tools.common.Rotation
+import android.tools.NavBar
+import android.tools.Rotation
 import android.tools.device.apphelpers.MessagingAppHelper
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
-import android.tools.device.flicker.rules.LaunchAppRule
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.flicker.rules.LaunchAppRule
+import android.tools.flicker.rules.RemoveAllTasksButHomeRule
 import androidx.test.platform.app.InstrumentationRegistry
 import org.junit.rules.RuleChain
 
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt
index b3c9c96..8040610 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.close.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.close.scenarios.CloseAppBackButton
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt
index 29c11a4..aacccf4 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.close.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.close.scenarios.CloseAppBackButton
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt
index 1bb4a25..74ee460 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.close.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.close.scenarios.CloseAppBackButton
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt
index 17cb6e1..57463c3 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.close.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.close.scenarios.CloseAppBackButton
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt
index 47c2529..3d5f0f2 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.close.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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.close.scenarios.CloseAppHomeButton
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt
index b18148f..055cc72 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.close.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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.close.scenarios.CloseAppHomeButton
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt
index 8543015..3877981 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.close.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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.close.scenarios.CloseAppSwipeToHome
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt
index f88963b..ef7755e 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.close.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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.close.scenarios.CloseAppSwipeToHome
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt
index 2aaacde..17de268 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.service.close.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt
index 08683a3..d8a88d4 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.service.close.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt
index 360e114..f32f5ba 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.service.close.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt
index bb18770..8b08750 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationCold
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt
index 1c3cc21..cc7fe4d 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationCold
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt
index 46d36db..f6414ca 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationCold
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt
index f6a668fe..4244900 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationCold
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt
index 93200ba..548acbe0 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWarm
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt
index f5d41d2..b231dd3 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWarm
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt
index 28f322b..14f680a 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWarm
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt
index beb3fae..6e07174 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWarm
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt
index 4adcc8b..de71b9a 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp
 import org.junit.Ignore
 import org.junit.Test
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt
index f7211e7..714d5e8a 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp
 import org.junit.Ignore
 import org.junit.Test
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt
index 1ade956..4c1bae7 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp
 import org.junit.Ignore
 import org.junit.Test
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt
index ea26f08..0321f77 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp
 import org.junit.Ignore
 import org.junit.Test
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt
index 866190f..e3b434d 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationCold
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt
index a8d6283..64bce2e 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationCold
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt
index ef84c3f..83241bf 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationCold
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt
index 5bb6b37..06b89d3 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationCold
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt
index 39f25e9..8d3cf90 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationWarm
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt
index 28816bc..0d0adf2 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationWarm
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt
index 94ffe4e..1fbaddb 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationWarm
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt
index e5f5ec4..52df4bd 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-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 android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationWarm
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt
index ac4e169..79d6bb7 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.service.notification.scenarios
 
 import android.app.Instrumentation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
 import android.view.WindowInsets
 import android.view.WindowManager
 import androidx.test.platform.app.InstrumentationRegistry
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt
index 9c53ab3..e702f12 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.service.notification.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt
index 31f55d9..0a509f8 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.service.notification.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt
index b971555..ce6ee2f 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.service.notification.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt
index fed077e..e1cf322 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.service.notification.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt
index 403790e..4dd84bd 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.service.notification.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt
index d611a42..da9f4bb 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.quickswitch.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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchBetweenTwoAppsBack
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt
index e6bcbba..f3ae920 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.quickswitch.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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchBetweenTwoAppsBack
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt
index 2a26d63..a26906c 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.quickswitch.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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchBetweenTwoAppsForward
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt
index 5ce7143..01def0e 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.quickswitch.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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchBetweenTwoAppsForward
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt
index cff47bb..3f40e56 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.quickswitch.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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchFromLauncher
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt
index 33095a6..70a95fe 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.quickswitch.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 android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchFromLauncher
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt
index a1708fe..f0df37a 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.service.quickswitch.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
index fcf442a..a22bdce 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.service.quickswitch.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt
index 7afe526..e5aa181 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.service.quickswitch.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
index 99e8ef5..7e486ab 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
@@ -17,13 +17,13 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.subject.region.RegionSubject
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.subject.region.RegionSubject
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeEditorPopupDialogAppHelper
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
index 48c54ea..2f3ec63 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
@@ -18,12 +18,12 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeAppHelper
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
index 31d5d7f..8821b69 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
index 180ae5d..d75eba6 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
index a0573b7..41d9e30 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
@@ -18,11 +18,11 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeAppHelper
 import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
index be47ec7..0e7fb79 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
@@ -18,13 +18,13 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeAppHelper
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
index 994edc5..47a7e1b 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
@@ -16,15 +16,15 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.subject.region.RegionSubject
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.subject.region.RegionSubject
+import android.tools.helpers.WindowUtils
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
index ea7c7c4..e8249bc 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
@@ -18,13 +18,13 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.subject.layers.LayerTraceEntrySubject
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
index b7a183d..617237d 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
 import com.android.server.wm.flicker.helpers.setRotation
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
index 6ee5a9a..7b62c89 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
@@ -17,13 +17,13 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
index 1ad5c0d..53bfb4e 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
 import com.android.server.wm.flicker.helpers.ImeStateInitializeHelper
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
index 918e1ea..12290af 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
@@ -18,11 +18,11 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeAppHelper
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
index 181a2a2..0948351 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
@@ -17,13 +17,13 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import android.view.WindowInsets.Type.ime
 import android.view.WindowInsets.Type.navigationBars
 import android.view.WindowInsets.Type.statusBars
@@ -55,10 +55,12 @@
             testApp.launchViaIntent(wmHelper)
             testApp.waitIMEShown(wmHelper)
             broadcastActionTrigger.doAction(ACTION_START_DIALOG_THEMED_ACTIVITY)
-            wmHelper.StateSyncBuilder()
-                    .withFullScreenApp(
-                        ActivityOptions.DialogThemedActivity.COMPONENT.toFlickerComponent())
-                    .waitForAndVerify()
+            wmHelper
+                .StateSyncBuilder()
+                .withFullScreenApp(
+                    ActivityOptions.DialogThemedActivity.COMPONENT.toFlickerComponent()
+                )
+                .waitForAndVerify()
             // Verify IME insets isn't visible on dialog since it's non-IME focusable window
             assertFalse(testApp.getInsetsVisibleFromDialog(ime()))
             assertTrue(testApp.getInsetsVisibleFromDialog(statusBars()))
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
index f1bc125..a14dc62 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
@@ -17,13 +17,13 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.ConditionsFactory
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.ConditionsFactory
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
 import com.android.server.wm.flicker.navBarLayerIsVisibleAtStartAndEnd
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/common/CommonAssertions.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/common/CommonAssertions.kt
index 777231e..bd3d1ce 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/common/CommonAssertions.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/common/CommonAssertions.kt
@@ -18,8 +18,8 @@
 
 package com.android.server.wm.flicker.ime
 
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
 
 fun LegacyFlickerTest.imeLayerBecomesVisible() {
     assertLayers {
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/Consts.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/Consts.kt
index b81439e..edcee46 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/Consts.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/Consts.kt
@@ -16,7 +16,7 @@
 
 package com.android.server.wm.flicker.notification
 
-import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.traces.component.ComponentNameMatcher
 
 object Consts {
     val IMAGE_WALLPAPER = ComponentNameMatcher("", "com.android.systemui.wallpapers.ImageWallpaper")
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
index 620502e..ffaeead 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
@@ -20,12 +20,12 @@
 import android.platform.test.annotations.Presubmit
 import android.platform.test.rule.SettingOverrideRule
 import android.provider.Settings
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.RequiresDevice
 import org.junit.ClassRule
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
index 2a458ef8..6e67e19 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
@@ -19,11 +19,11 @@
 import android.platform.test.annotations.Presubmit
 import android.platform.test.rule.SettingOverrideRule
 import android.provider.Settings
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.statusBarLayerPositionAtEnd
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
index 00aad27..8e210d4 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
@@ -18,12 +18,12 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.ShowWhenLockedAppHelper
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
index f8d78b5..b6d09d0 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
@@ -18,12 +18,12 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.statusBarLayerPositionAtEnd
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
index 5c7ec46..1e607bf 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
@@ -18,13 +18,13 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTestData
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.FlickerTestData
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.component.ComponentNameMatcher
 import android.view.WindowInsets
 import android.view.WindowManager
 import androidx.test.uiautomator.By
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt
index 4e0e3c0..4ba444b 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.notification
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import org.junit.Test
diff --git a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
index 13fcc2b..8b09b59 100644
--- a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
+++ b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
@@ -17,13 +17,13 @@
 package com.android.server.wm.flicker.quickswitch
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.common.datatypes.Rect
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
diff --git a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
index badd7c8..c54ddcf 100644
--- a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
+++ b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.quickswitch
 
-import android.tools.common.NavBar
-import android.tools.common.datatypes.Rect
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
diff --git a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
index f51be90..69a84a0 100644
--- a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
+++ b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
@@ -17,14 +17,14 @@
 package com.android.server.wm.flicker.quickswitch
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.datatypes.Rect
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index bdbf0d2..05ab364 100644
--- a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -18,11 +18,11 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import org.junit.FixMethodOrder
 import org.junit.Test
diff --git a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
index 79d3a10..c7da778 100644
--- a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -17,13 +17,13 @@
 package com.android.server.wm.flicker.rotation
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.component.IComponentMatcher
-import android.tools.common.traces.surfaceflinger.Display
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.subject.layers.LayerTraceEntrySubject
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.component.IComponentMatcher
+import android.tools.traces.surfaceflinger.Display
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.setRotation
 import org.junit.Test
@@ -76,9 +76,9 @@
     }
 
     private fun LayerTraceEntrySubject.getDisplay(componentMatcher: IComponentMatcher): Display {
-        val stackId = this.layer {
-            componentMatcher.layerMatchesAnyOf(it) && it.isVisible
-        }?.layer?.stackId ?: -1
+        val stackId =
+            this.layer { componentMatcher.layerMatchesAnyOf(it) && it.isVisible }?.layer?.stackId
+                ?: -1
 
         return this.entry.displays.firstOrNull { it.layerStackId == stackId }
             ?: error("Unable to find visible layer for $componentMatcher")
diff --git a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index 6d3ae43..a413628 100644
--- a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -18,13 +18,13 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.ScenarioBuilder
-import android.tools.common.ScenarioImpl
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.ScenarioBuilder
+import android.tools.ScenarioImpl
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import android.view.WindowManager
 import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
index ce92eac..17f91eb 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
@@ -19,10 +19,10 @@
 import android.app.Instrumentation
 import android.content.Intent
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerBuilderProvider
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerBuilderProvider
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
 import android.util.Log
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index 1abb8c2..8853c1d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -18,15 +18,15 @@
 
 package com.android.server.wm.flicker
 
-import android.tools.common.PlatformConsts
-import android.tools.common.Position
-import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
-import android.tools.common.flicker.subject.region.RegionSubject
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.component.IComponentNameMatcher
-import android.tools.common.traces.wm.WindowManagerTrace
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.helpers.WindowUtils
+import android.tools.PlatformConsts
+import android.tools.Position
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.subject.layers.LayerTraceEntrySubject
+import android.tools.flicker.subject.region.RegionSubject
+import android.tools.helpers.WindowUtils
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.component.IComponentNameMatcher
+import android.tools.traces.wm.WindowManagerTrace
 
 /**
  * Checks that [ComponentNameMatcher.STATUS_BAR] window is visible and above the app windows in all
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
index 11e6bbe..4a675be 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.PlatformConsts
-import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.PlatformConsts
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import android.util.Log
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt
index 94ac1a6..ec661d7 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt
@@ -17,8 +17,8 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
+import android.tools.traces.component.ComponentNameMatcher
 
 class AppPairsHelper(
     instrumentation: Instrumentation,
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
index fde0981..5333725 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
@@ -19,7 +19,7 @@
 import android.app.Instrumentation
 import android.content.ComponentName
 import android.provider.Settings
-import android.tools.device.helpers.FIND_TIMEOUT
+import android.tools.helpers.FIND_TIMEOUT
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiDevice
 import androidx.test.uiautomator.Until
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
index c6fa1bb..1915225 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
 
 class FixedOrientationAppHelper
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
index 5c8cbe4..926209f 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
@@ -18,9 +18,9 @@
 
 package com.android.server.wm.flicker.helpers
 
-import android.tools.common.Rotation
-import android.tools.device.flicker.legacy.FlickerTestData
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.Rotation
+import android.tools.flicker.legacy.FlickerTestData
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
 
 /**
  * Changes the device [rotation] and wait for the rotation animation to complete
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
index 3146139..0c60f28 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Direction
 import androidx.test.uiautomator.Until
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
index cb1aab0..495fbce 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt
index 7a8d780..6fe7c29 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
index 0ee7aee..f5c88e3 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
@@ -17,13 +17,13 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.component.IComponentMatcher
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.helpers.IME_PACKAGE
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.Rotation
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.helpers.IME_PACKAGE
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.component.IComponentMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import android.view.WindowInsets.Type.ime
 import android.view.WindowInsets.Type.navigationBars
 import android.view.WindowInsets.Type.statusBars
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
index b2aeb14..db93bf7 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
 
 class ImeStateInitializeHelper
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt
index b95d86b..d6ead85 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt
@@ -18,7 +18,7 @@
 
 import android.app.Instrumentation
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
 
 class LaunchBubbleHelper(instrumentation: Instrumentation) :
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
index 9b539c8..b09e53b 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
@@ -17,14 +17,14 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.datatypes.Rect
-import android.tools.common.datatypes.Region
-import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.datatypes.Rect
+import android.tools.datatypes.Region
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.helpers.SYSTEMUI_PACKAGE
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.helpers.SYSTEMUI_PACKAGE
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
index 9895bda..d4075e9 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Direction
 import androidx.test.uiautomator.UiObject2
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt
index 65175ef..29c1cde 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt
@@ -19,8 +19,8 @@
 import android.app.Instrumentation
 import android.content.Context
 import android.provider.Settings
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
+import android.tools.traces.component.ComponentNameMatcher
 import android.util.Log
 import com.android.compatibility.common.util.SystemUtil
 import java.io.IOException
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
index b2f8d47..ea4ea0a 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiDevice
 import androidx.test.uiautomator.Until
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
index ee65004..ebf3487 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
 
 class NonResizeableAppHelper
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
index e60c20d..c559d0f 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index 452c98c..db933b3 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -20,15 +20,15 @@
 import android.content.Intent
 import android.media.session.MediaController
 import android.media.session.MediaSessionManager
-import android.tools.common.datatypes.Rect
-import android.tools.common.datatypes.Region
-import android.tools.common.traces.ConditionsFactory
-import android.tools.common.traces.component.IComponentMatcher
+import android.tools.datatypes.Rect
+import android.tools.datatypes.Region
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.helpers.SYSTEMUI_PACKAGE
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.helpers.SYSTEMUI_PACKAGE
+import android.tools.traces.ConditionsFactory
+import android.tools.traces.component.IComponentMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import android.util.Log
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
index cac3530..55d43e6 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
 
 class SeamlessRotationAppHelper
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
index 8366a7a..05856cc 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
 
 class ShowWhenLockedAppHelper
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
index 89c6c35..82ef398 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
 
 class SimpleAppHelper
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt
index 6311678..ffe077e 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
 
 class TransferSplashscreenAppHelper
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
index 8be5769..867bcb6 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiDevice
 import androidx.test.uiautomator.Until
diff --git a/tests/GamePerformance/src/android/gameperformance/GamePerformanceTest.java b/tests/GamePerformance/src/android/gameperformance/GamePerformanceTest.java
index d6e2861..cc0255d 100644
--- a/tests/GamePerformance/src/android/gameperformance/GamePerformanceTest.java
+++ b/tests/GamePerformance/src/android/gameperformance/GamePerformanceTest.java
@@ -15,6 +15,14 @@
  */
 package android.gameperformance;
 
+import android.annotation.NonNull;
+import android.app.Activity;
+import android.os.Bundle;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import androidx.test.filters.SmallTest;
+
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -22,18 +30,6 @@
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 
-import android.annotation.NonNull;
-import android.app.Activity;
-import android.content.Context;
-import android.graphics.PixelFormat;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Debug;
-import android.os.Trace;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
 public class GamePerformanceTest extends
         ActivityInstrumentationTestCase2<GamePerformanceActivity> {
     private final static String TAG = "GamePerformanceTest";
diff --git a/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt b/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt
index 7343ba1c..e60764f 100644
--- a/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt
@@ -24,6 +24,7 @@
 import android.content.pm.PackageManager
 import android.content.pm.ResolveInfo
 import android.content.pm.ServiceInfo
+import android.hardware.input.KeyboardLayoutSelectionResult
 import android.hardware.input.IInputManager
 import android.hardware.input.InputManager
 import android.hardware.input.InputManagerGlobal
@@ -525,13 +526,13 @@
                 keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype,
                 ENGLISH_UK_LAYOUT_DESCRIPTOR
             )
-            val keyboardLayout =
+            assertEquals(
+                "Default UI: getKeyboardLayoutForInputDevice API should always return " +
+                        "KeyboardLayoutSelectionResult.FAILED",
+                KeyboardLayoutSelectionResult.FAILED,
                 keyboardLayoutManager.getKeyboardLayoutForInputDevice(
                     keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype
                 )
-            assertNull(
-                "Default UI: getKeyboardLayoutForInputDevice API should always return null",
-                keyboardLayout
             )
         }
     }
@@ -545,12 +546,14 @@
                 keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype,
                 ENGLISH_UK_LAYOUT_DESCRIPTOR
             )
-            assertEquals(
-                "New UI: getKeyboardLayoutForInputDevice API should return the set layout",
-                ENGLISH_UK_LAYOUT_DESCRIPTOR,
+            var result =
                 keyboardLayoutManager.getKeyboardLayoutForInputDevice(
                     keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype
                 )
+            assertEquals(
+                "New UI: getKeyboardLayoutForInputDevice API should return the set layout",
+                ENGLISH_UK_LAYOUT_DESCRIPTOR,
+                result.layoutDescriptor
             )
 
             // This should replace previously set layout
@@ -558,12 +561,14 @@
                 keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype,
                 ENGLISH_US_LAYOUT_DESCRIPTOR
             )
-            assertEquals(
-                "New UI: getKeyboardLayoutForInputDevice API should return the last set layout",
-                ENGLISH_US_LAYOUT_DESCRIPTOR,
+            result =
                 keyboardLayoutManager.getKeyboardLayoutForInputDevice(
                     keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype
                 )
+            assertEquals(
+                "New UI: getKeyboardLayoutForInputDevice API should return the last set layout",
+                ENGLISH_US_LAYOUT_DESCRIPTOR,
+                result.layoutDescriptor
             )
         }
     }
@@ -734,17 +739,20 @@
                 createImeSubtypeForLanguageTag("ru"),
                 createLayoutDescriptor("keyboard_layout_russian")
             )
-            assertNull(
-                "New UI: getDefaultKeyboardLayoutForInputDevice should return null when no " +
-                        "layout available",
+            assertEquals(
+                "New UI: getDefaultKeyboardLayoutForInputDevice should return " +
+                        "KeyboardLayoutSelectionResult.FAILED when no layout available",
+                KeyboardLayoutSelectionResult.FAILED,
                 keyboardLayoutManager.getKeyboardLayoutForInputDevice(
                     keyboardDevice.identifier, USER_ID, imeInfo,
                     createImeSubtypeForLanguageTag("it")
                 )
             )
-            assertNull(
-                "New UI: getDefaultKeyboardLayoutForInputDevice should return null when no " +
-                        "layout for script code is available",
+            assertEquals(
+                "New UI: getDefaultKeyboardLayoutForInputDevice should return " +
+                        "KeyboardLayoutSelectionResult.FAILED when no layout for script code is" +
+                        "available",
+                KeyboardLayoutSelectionResult.FAILED,
                 keyboardLayoutManager.getKeyboardLayoutForInputDevice(
                     keyboardDevice.identifier, USER_ID, imeInfo,
                     createImeSubtypeForLanguageTag("en-Deva")
@@ -811,8 +819,10 @@
                 createImeSubtypeForLanguageTagAndLayoutType("ru", ""),
                 createLayoutDescriptor("keyboard_layout_russian")
             )
-            assertNull("New UI: getDefaultKeyboardLayoutForInputDevice should return null when " +
-                    "no layout for script code is available",
+            assertEquals("New UI: getDefaultKeyboardLayoutForInputDevice should return " +
+                    "KeyboardLayoutSelectionResult.FAILED when no layout for script code is" +
+                    "available",
+                KeyboardLayoutSelectionResult.FAILED,
                 keyboardLayoutManager.getKeyboardLayoutForInputDevice(
                     keyboardDevice.identifier, USER_ID, imeInfo,
                     createImeSubtypeForLanguageTagAndLayoutType("en-Deva-US", "")
@@ -865,14 +875,16 @@
                         ArgumentMatchers.anyBoolean(),
                         ArgumentMatchers.eq(keyboardDevice.vendorId),
                         ArgumentMatchers.eq(keyboardDevice.productId),
-                        ArgumentMatchers.eq(createByteArray(
+                        ArgumentMatchers.eq(
+                            createByteArray(
                                 KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG,
                                 LAYOUT_TYPE_DEFAULT,
                                 GERMAN_LAYOUT_NAME,
-                                KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD,
+                                KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD,
                                 "de-Latn",
-                                LAYOUT_TYPE_QWERTZ),
+                                LAYOUT_TYPE_QWERTZ
                             ),
+                        ),
                         ArgumentMatchers.eq(keyboardDevice.deviceBus),
                 )
             }
@@ -893,13 +905,16 @@
                         ArgumentMatchers.anyBoolean(),
                         ArgumentMatchers.eq(englishQwertyKeyboardDevice.vendorId),
                         ArgumentMatchers.eq(englishQwertyKeyboardDevice.productId),
-                        ArgumentMatchers.eq(createByteArray(
+                        ArgumentMatchers.eq(
+                            createByteArray(
                                 "en",
                                 LAYOUT_TYPE_QWERTY,
                                 ENGLISH_US_LAYOUT_NAME,
-                                KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEVICE,
+                                KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEVICE,
                                 "de-Latn",
-                                LAYOUT_TYPE_QWERTZ)),
+                                LAYOUT_TYPE_QWERTZ
+                            )
+                        ),
                         ArgumentMatchers.eq(keyboardDevice.deviceBus),
                 )
             }
@@ -918,14 +933,16 @@
                         ArgumentMatchers.anyBoolean(),
                         ArgumentMatchers.eq(keyboardDevice.vendorId),
                         ArgumentMatchers.eq(keyboardDevice.productId),
-                        ArgumentMatchers.eq(createByteArray(
+                        ArgumentMatchers.eq(
+                            createByteArray(
                                 KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG,
                                 LAYOUT_TYPE_DEFAULT,
                                 "Default",
-                                KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEFAULT,
+                                KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEFAULT,
                                 KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG,
-                                LAYOUT_TYPE_DEFAULT),
+                                LAYOUT_TYPE_DEFAULT
                             ),
+                        ),
                         ArgumentMatchers.eq(keyboardDevice.deviceBus),
                 )
             }
@@ -998,12 +1015,13 @@
         imeSubtype: InputMethodSubtype,
         expectedLayout: String
     ) {
+        val result = keyboardLayoutManager.getKeyboardLayoutForInputDevice(
+            device.identifier, USER_ID, imeInfo, imeSubtype
+        )
         assertEquals(
             "New UI: getDefaultKeyboardLayoutForInputDevice should return $expectedLayout",
             expectedLayout,
-            keyboardLayoutManager.getKeyboardLayoutForInputDevice(
-                device.identifier, USER_ID, imeInfo, imeSubtype
-            )
+            result.layoutDescriptor
         )
     }
 
diff --git a/tests/Input/src/com/android/server/input/KeyboardMetricsCollectorTests.kt b/tests/Input/src/com/android/server/input/KeyboardMetricsCollectorTests.kt
index 89a47b9..0615941 100644
--- a/tests/Input/src/com/android/server/input/KeyboardMetricsCollectorTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyboardMetricsCollectorTests.kt
@@ -17,6 +17,7 @@
 package com.android.server.input
 
 import android.hardware.input.KeyboardLayout
+import android.hardware.input.KeyboardLayoutSelectionResult
 import android.icu.util.ULocale
 import android.platform.test.annotations.Presubmit
 import android.view.InputDevice
@@ -120,15 +121,15 @@
         val event = builder.addLayoutSelection(
             createImeSubtype(1, ULocale.forLanguageTag("en-US"), "qwerty"),
             "English(US)(Qwerty)",
-            KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD
+            KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD
         ).addLayoutSelection(
             createImeSubtype(2, ULocale.forLanguageTag("en-US"), "azerty"),
             null, // Default layout type
-            KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_USER
+            KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_USER
         ).addLayoutSelection(
             createImeSubtype(3, ULocale.forLanguageTag("en-US"), "qwerty"),
             "German",
-            KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEVICE
+            KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEVICE
         ).setIsFirstTimeConfiguration(true).build()
 
         assertEquals(
@@ -158,7 +159,7 @@
             "de-CH",
             KeyboardLayout.LayoutType.getLayoutTypeEnumValue("qwertz"),
             "English(US)(Qwerty)",
-            KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD,
+            KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD,
             "en-US",
             KeyboardLayout.LayoutType.getLayoutTypeEnumValue("qwerty"),
         )
@@ -167,7 +168,7 @@
             "de-CH",
             KeyboardLayout.LayoutType.getLayoutTypeEnumValue("qwertz"),
             KeyboardMetricsCollector.DEFAULT_LAYOUT_NAME,
-            KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_USER,
+            KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_USER,
             "en-US",
             KeyboardLayout.LayoutType.getLayoutTypeEnumValue("azerty"),
         )
@@ -176,7 +177,7 @@
             "de-CH",
             KeyboardLayout.LayoutType.getLayoutTypeEnumValue("qwertz"),
             "German",
-            KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEVICE,
+            KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEVICE,
             "en-US",
             KeyboardLayout.LayoutType.getLayoutTypeEnumValue("qwerty"),
         )
@@ -197,7 +198,7 @@
         val event = builder.addLayoutSelection(
             createImeSubtype(4, null, "qwerty"), // Default language tag
             "German",
-            KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEVICE
+            KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEVICE
         ).build()
 
         assertExpectedLayoutConfiguration(
@@ -205,7 +206,7 @@
             KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG,
             KeyboardLayout.LayoutType.getLayoutTypeEnumValue("azerty"),
             "German",
-            KeyboardMetricsCollector.LAYOUT_SELECTION_CRITERIA_DEVICE,
+            KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEVICE,
             KeyboardMetricsCollector.DEFAULT_LANGUAGE_TAG,
             KeyboardLayout.LayoutType.getLayoutTypeEnumValue("qwerty"),
         )
diff --git a/tests/Internal/Android.bp b/tests/Internal/Android.bp
index a487799..827ff4f 100644
--- a/tests/Internal/Android.bp
+++ b/tests/Internal/Android.bp
@@ -21,6 +21,9 @@
         "mockito-target-minus-junit4",
         "truth",
         "platform-test-annotations",
+        "flickerlib-parsers",
+        "perfetto_trace_java_protos",
+        "flickerlib-trace_processor_shell",
     ],
     java_resource_dirs: ["res"],
     certificate: "platform",
diff --git a/tests/Internal/AndroidManifest.xml b/tests/Internal/AndroidManifest.xml
index dbba245..9a3fe61 100644
--- a/tests/Internal/AndroidManifest.xml
+++ b/tests/Internal/AndroidManifest.xml
@@ -19,7 +19,11 @@
      package="com.android.internal.tests">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.BIND_WALLPAPER"/>
-    <application>
+    <!-- Allow the test to connect to perfetto trace processor -->
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <application
+        android:requestLegacyExternalStorage="true"
+        android:networkSecurityConfig="@xml/network_security_config">
         <uses-library android:name="android.test.runner"/>
 
         <service android:name="stub.DummyWallpaperService"
diff --git a/tests/Internal/res/xml/network_security_config.xml b/tests/Internal/res/xml/network_security_config.xml
new file mode 100644
index 0000000..fdf1dbb
--- /dev/null
+++ b/tests/Internal/res/xml/network_security_config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<network-security-config>
+    <domain-config cleartextTrafficPermitted="true">
+        <domain includeSubdomains="true">localhost</domain>
+    </domain-config>
+</network-security-config>
diff --git a/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogImplTest.java
new file mode 100644
index 0000000..a64996c
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogImplTest.java
@@ -0,0 +1,396 @@
+/*
+ * 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.internal.protolog;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.internal.protolog.LegacyProtoLogImpl.PROTOLOG_VERSION;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
+import android.util.proto.ProtoInputStream;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.protolog.common.IProtoLogGroup;
+import com.android.internal.protolog.common.LogLevel;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.LinkedList;
+
+/**
+ * Test class for {@link ProtoLogImpl}.
+ */
+@SuppressWarnings("ConstantConditions")
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class LegacyProtoLogImplTest {
+
+    private static final byte[] MAGIC_HEADER = new byte[]{
+            0x9, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x4c, 0x4f, 0x47
+    };
+
+    private LegacyProtoLogImpl mProtoLog;
+    private File mFile;
+
+    @Mock
+    private LegacyProtoLogViewerConfigReader mReader;
+
+    private final String mViewerConfigFilename = "unused/file/path";
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        final Context testContext = getInstrumentation().getContext();
+        mFile = testContext.getFileStreamPath("tracing_test.dat");
+        //noinspection ResultOfMethodCallIgnored
+        mFile.delete();
+        mProtoLog = new LegacyProtoLogImpl(mFile, mViewerConfigFilename,
+                1024 * 1024, mReader, 1024);
+    }
+
+    @After
+    public void tearDown() {
+        if (mFile != null) {
+            //noinspection ResultOfMethodCallIgnored
+            mFile.delete();
+        }
+        ProtoLogImpl.setSingleInstance(null);
+    }
+
+    @Test
+    public void isEnabled_returnsFalseByDefault() {
+        assertFalse(mProtoLog.isProtoEnabled());
+    }
+
+    @Test
+    public void isEnabled_returnsTrueAfterStart() {
+        mProtoLog.startProtoLog(mock(PrintWriter.class));
+        assertTrue(mProtoLog.isProtoEnabled());
+    }
+
+    @Test
+    public void isEnabled_returnsFalseAfterStop() {
+        mProtoLog.startProtoLog(mock(PrintWriter.class));
+        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+        assertFalse(mProtoLog.isProtoEnabled());
+    }
+
+    @Test
+    public void logFile_startsWithMagicHeader() throws Exception {
+        mProtoLog.startProtoLog(mock(PrintWriter.class));
+        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+
+        assertTrue("Log file should exist", mFile.exists());
+
+        byte[] header = new byte[MAGIC_HEADER.length];
+        try (InputStream is = new FileInputStream(mFile)) {
+            assertEquals(MAGIC_HEADER.length, is.read(header));
+            assertArrayEquals(MAGIC_HEADER, header);
+        }
+    }
+
+    @Test
+    public void log_logcatEnabledExternalMessage() {
+        when(mReader.getViewerString(anyLong())).thenReturn("test %b %d %% 0x%x %s %f");
+        LegacyProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+                new Object[]{true, 10000, 30000, "test", 0.000003});
+
+        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+                LogLevel.INFO),
+                eq("test true 10000 % 0x7530 test 3.0E-6"));
+        verify(mReader).getViewerString(eq(1234L));
+    }
+
+    @Test
+    public void log_logcatEnabledInvalidMessage() {
+        when(mReader.getViewerString(anyLong())).thenReturn("test %b %d %% %x %s %f");
+        LegacyProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+                new Object[]{true, 10000, 0.0001, 0.00002, "test"});
+
+        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+                LogLevel.INFO),
+                eq("UNKNOWN MESSAGE (1234) true 10000 1.0E-4 2.0E-5 test"));
+        verify(mReader).getViewerString(eq(1234L));
+    }
+
+    @Test
+    public void log_logcatEnabledInlineMessage() {
+        when(mReader.getViewerString(anyLong())).thenReturn("test %d");
+        LegacyProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d",
+                new Object[]{5});
+
+        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+                LogLevel.INFO), eq("test 5"));
+        verify(mReader, never()).getViewerString(anyLong());
+    }
+
+    @Test
+    public void log_logcatEnabledNoMessage() {
+        when(mReader.getViewerString(anyLong())).thenReturn(null);
+        LegacyProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+                new Object[]{5});
+
+        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+                LogLevel.INFO), eq("UNKNOWN MESSAGE (1234) 5"));
+        verify(mReader).getViewerString(eq(1234L));
+    }
+
+    @Test
+    public void log_logcatDisabled() {
+        when(mReader.getViewerString(anyLong())).thenReturn("test %d");
+        LegacyProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d",
+                new Object[]{5});
+
+        verify(implSpy, never()).passToLogcat(any(), any(), any());
+        verify(mReader, never()).getViewerString(anyLong());
+    }
+
+    private static class ProtoLogData {
+        Long mMessageHash = null;
+        Long mElapsedTime = null;
+        LinkedList<String> mStrParams = new LinkedList<>();
+        LinkedList<Long> mSint64Params = new LinkedList<>();
+        LinkedList<Double> mDoubleParams = new LinkedList<>();
+        LinkedList<Boolean> mBooleanParams = new LinkedList<>();
+    }
+
+    private ProtoLogData readProtoLogSingle(ProtoInputStream ip) throws IOException {
+        while (ip.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            if (ip.getFieldNumber() == (int) ProtoLogFileProto.VERSION) {
+                assertEquals(PROTOLOG_VERSION, ip.readString(ProtoLogFileProto.VERSION));
+                continue;
+            }
+            if (ip.getFieldNumber() != (int) ProtoLogFileProto.LOG) {
+                continue;
+            }
+            long token = ip.start(ProtoLogFileProto.LOG);
+            ProtoLogData data = new ProtoLogData();
+            while (ip.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                switch (ip.getFieldNumber()) {
+                    case (int) ProtoLogMessage.MESSAGE_HASH: {
+                        data.mMessageHash = ip.readLong(ProtoLogMessage.MESSAGE_HASH);
+                        break;
+                    }
+                    case (int) ProtoLogMessage.ELAPSED_REALTIME_NANOS: {
+                        data.mElapsedTime = ip.readLong(ProtoLogMessage.ELAPSED_REALTIME_NANOS);
+                        break;
+                    }
+                    case (int) ProtoLogMessage.STR_PARAMS: {
+                        data.mStrParams.add(ip.readString(ProtoLogMessage.STR_PARAMS));
+                        break;
+                    }
+                    case (int) ProtoLogMessage.SINT64_PARAMS: {
+                        data.mSint64Params.add(ip.readLong(ProtoLogMessage.SINT64_PARAMS));
+                        break;
+                    }
+                    case (int) ProtoLogMessage.DOUBLE_PARAMS: {
+                        data.mDoubleParams.add(ip.readDouble(ProtoLogMessage.DOUBLE_PARAMS));
+                        break;
+                    }
+                    case (int) ProtoLogMessage.BOOLEAN_PARAMS: {
+                        data.mBooleanParams.add(ip.readBoolean(ProtoLogMessage.BOOLEAN_PARAMS));
+                        break;
+                    }
+                }
+            }
+            ip.end(token);
+            return data;
+        }
+        return null;
+    }
+
+    @Test
+    public void log_protoEnabled() throws Exception {
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(true);
+        mProtoLog.startProtoLog(mock(PrintWriter.class));
+        long before = SystemClock.elapsedRealtimeNanos();
+        mProtoLog.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
+                0b1110101001010100, null,
+                new Object[]{"test", 1, 2, 3, 0.4, 0.5, 0.6, true});
+        long after = SystemClock.elapsedRealtimeNanos();
+        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+        try (InputStream is = new FileInputStream(mFile)) {
+            ProtoInputStream ip = new ProtoInputStream(is);
+            ProtoLogData data = readProtoLogSingle(ip);
+            assertNotNull(data);
+            assertEquals(1234, data.mMessageHash.longValue());
+            assertTrue(before <= data.mElapsedTime && data.mElapsedTime <= after);
+            assertArrayEquals(new String[]{"test"}, data.mStrParams.toArray());
+            assertArrayEquals(new Long[]{1L, 2L, 3L}, data.mSint64Params.toArray());
+            assertArrayEquals(new Double[]{0.4, 0.5, 0.6}, data.mDoubleParams.toArray());
+            assertArrayEquals(new Boolean[]{true}, data.mBooleanParams.toArray());
+        }
+    }
+
+    @Test
+    public void log_invalidParamsMask() throws Exception {
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(true);
+        mProtoLog.startProtoLog(mock(PrintWriter.class));
+        long before = SystemClock.elapsedRealtimeNanos();
+        mProtoLog.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
+                0b01100100, null,
+                new Object[]{"test", 1, 0.1, true});
+        long after = SystemClock.elapsedRealtimeNanos();
+        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+        try (InputStream is = new FileInputStream(mFile)) {
+            ProtoInputStream ip = new ProtoInputStream(is);
+            ProtoLogData data = readProtoLogSingle(ip);
+            assertNotNull(data);
+            assertEquals(1234, data.mMessageHash.longValue());
+            assertTrue(before <= data.mElapsedTime && data.mElapsedTime <= after);
+            assertArrayEquals(new String[]{"test", "(INVALID PARAMS_MASK) true"},
+                    data.mStrParams.toArray());
+            assertArrayEquals(new Long[]{1L}, data.mSint64Params.toArray());
+            assertArrayEquals(new Double[]{0.1}, data.mDoubleParams.toArray());
+            assertArrayEquals(new Boolean[]{}, data.mBooleanParams.toArray());
+        }
+    }
+
+    @Test
+    public void log_protoDisabled() throws Exception {
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+        mProtoLog.startProtoLog(mock(PrintWriter.class));
+        mProtoLog.log(LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
+                0b11, null, new Object[]{true});
+        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+        try (InputStream is = new FileInputStream(mFile)) {
+            ProtoInputStream ip = new ProtoInputStream(is);
+            ProtoLogData data = readProtoLogSingle(ip);
+            assertNull(data);
+        }
+    }
+
+    private enum TestProtoLogGroup implements IProtoLogGroup {
+        TEST_GROUP(true, true, false, "WindowManagetProtoLogTest");
+
+        private final boolean mEnabled;
+        private volatile boolean mLogToProto;
+        private volatile boolean mLogToLogcat;
+        private final String mTag;
+
+        /**
+         * @param enabled     set to false to exclude all log statements for this group from
+         *                    compilation,
+         *                    they will not be available in runtime.
+         * @param logToProto  enable binary logging for the group
+         * @param logToLogcat enable text logging for the group
+         * @param tag         name of the source of the logged message
+         */
+        TestProtoLogGroup(boolean enabled, boolean logToProto, boolean logToLogcat, String tag) {
+            this.mEnabled = enabled;
+            this.mLogToProto = logToProto;
+            this.mLogToLogcat = logToLogcat;
+            this.mTag = tag;
+        }
+
+        @Override
+        public boolean isEnabled() {
+            return mEnabled;
+        }
+
+        @Override
+        public boolean isLogToProto() {
+            return mLogToProto;
+        }
+
+        @Override
+        public boolean isLogToLogcat() {
+            return mLogToLogcat;
+        }
+
+        @Override
+        public boolean isLogToAny() {
+            return mLogToLogcat || mLogToProto;
+        }
+
+        @Override
+        public String getTag() {
+            return mTag;
+        }
+
+        @Override
+        public void setLogToProto(boolean logToProto) {
+            this.mLogToProto = logToProto;
+        }
+
+        @Override
+        public void setLogToLogcat(boolean logToLogcat) {
+            this.mLogToLogcat = logToLogcat;
+        }
+
+    }
+}
diff --git a/tests/Internal/src/com/android/internal/protolog/PerfettoDataSourceTest.java b/tests/Internal/src/com/android/internal/protolog/PerfettoDataSourceTest.java
new file mode 100644
index 0000000..a963890
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/protolog/PerfettoDataSourceTest.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.protolog;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import android.tracing.perfetto.CreateTlsStateArgs;
+import android.util.proto.ProtoInputStream;
+
+import com.android.internal.protolog.common.LogLevel;
+
+import com.google.common.truth.Truth;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import perfetto.protos.DataSourceConfigOuterClass;
+import perfetto.protos.ProtologCommon;
+import perfetto.protos.ProtologConfig;
+
+public class PerfettoDataSourceTest {
+    @Before
+    public void before() {
+        assumeTrue(android.tracing.Flags.perfettoProtologTracing());
+    }
+
+    @Test
+    public void noConfig() {
+        final ProtoLogDataSource.TlsState tlsState = createTlsState(
+                DataSourceConfigOuterClass.DataSourceConfig.newBuilder().build());
+
+        Truth.assertThat(tlsState.getLogFromLevel("SOME_TAG")).isEqualTo(LogLevel.WTF);
+        Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_TAG")).isFalse();
+    }
+
+    @Test
+    public void defaultTraceMode() {
+        final ProtoLogDataSource.TlsState tlsState = createTlsState(
+                DataSourceConfigOuterClass.DataSourceConfig.newBuilder()
+                        .setProtologConfig(
+                                ProtologConfig.ProtoLogConfig.newBuilder()
+                                        .setTracingMode(
+                                                ProtologConfig.ProtoLogConfig.TracingMode
+                                                        .ENABLE_ALL)
+                                        .build()
+                        ).build());
+
+        Truth.assertThat(tlsState.getLogFromLevel("SOME_TAG")).isEqualTo(LogLevel.DEBUG);
+        Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_TAG")).isFalse();
+    }
+
+    @Test
+    public void allEnabledTraceMode() {
+        final ProtoLogDataSource ds = new ProtoLogDataSource(() -> {}, () -> {}, () -> {});
+
+        final ProtoLogDataSource.TlsState tlsState = createTlsState(
+                DataSourceConfigOuterClass.DataSourceConfig.newBuilder().setProtologConfig(
+                        ProtologConfig.ProtoLogConfig.newBuilder()
+                                .setTracingMode(
+                                        ProtologConfig.ProtoLogConfig.TracingMode.ENABLE_ALL)
+                                .build()
+                ).build()
+        );
+
+        Truth.assertThat(tlsState.getLogFromLevel("SOME_TAG")).isEqualTo(LogLevel.DEBUG);
+        Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_TAG")).isFalse();
+    }
+
+    @Test
+    public void requireGroupTagInOverrides() {
+        Exception exception = assertThrows(RuntimeException.class, () -> {
+            createTlsState(DataSourceConfigOuterClass.DataSourceConfig.newBuilder()
+                    .setProtologConfig(
+                            ProtologConfig.ProtoLogConfig.newBuilder()
+                                    .addGroupOverrides(
+                                            ProtologConfig.ProtoLogGroup.newBuilder()
+                                                    .setLogFrom(
+                                                            ProtologCommon.ProtoLogLevel
+                                                                    .PROTOLOG_LEVEL_WARN)
+                                                    .setCollectStacktrace(true)
+                                    )
+                                    .build()
+                    ).build());
+        });
+
+        Truth.assertThat(exception).hasMessageThat().contains("group override without a group tag");
+    }
+
+    @Test
+    public void stackTraceCollection() {
+        final ProtoLogDataSource.TlsState tlsState = createTlsState(
+                DataSourceConfigOuterClass.DataSourceConfig.newBuilder().setProtologConfig(
+                        ProtologConfig.ProtoLogConfig.newBuilder()
+                                .addGroupOverrides(
+                                        ProtologConfig.ProtoLogGroup.newBuilder()
+                                                .setGroupName("SOME_TAG")
+                                                .setCollectStacktrace(true)
+                                )
+                                .build()
+                ).build());
+
+        Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_TAG")).isTrue();
+    }
+
+    @Test
+    public void groupLogFromOverrides() {
+        final ProtoLogDataSource.TlsState tlsState = createTlsState(
+                DataSourceConfigOuterClass.DataSourceConfig.newBuilder().setProtologConfig(
+                        ProtologConfig.ProtoLogConfig.newBuilder()
+                                .addGroupOverrides(
+                                        ProtologConfig.ProtoLogGroup.newBuilder()
+                                                .setGroupName("SOME_TAG")
+                                                .setLogFrom(
+                                                        ProtologCommon.ProtoLogLevel
+                                                                .PROTOLOG_LEVEL_DEBUG)
+                                                .setCollectStacktrace(true)
+                                )
+                                .addGroupOverrides(
+                                        ProtologConfig.ProtoLogGroup.newBuilder()
+                                                .setGroupName("SOME_OTHER_TAG")
+                                                .setLogFrom(
+                                                        ProtologCommon.ProtoLogLevel
+                                                                .PROTOLOG_LEVEL_WARN)
+                                )
+                                .build()
+                ).build());
+
+        Truth.assertThat(tlsState.getLogFromLevel("SOME_TAG")).isEqualTo(LogLevel.DEBUG);
+        Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_TAG")).isTrue();
+
+        Truth.assertThat(tlsState.getLogFromLevel("SOME_OTHER_TAG")).isEqualTo(LogLevel.WARN);
+        Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_OTHER_TAG")).isFalse();
+
+        Truth.assertThat(tlsState.getLogFromLevel("UNKNOWN_TAG")).isEqualTo(LogLevel.WTF);
+        Truth.assertThat(tlsState.getShouldCollectStacktrace("UNKNOWN_TAG")).isFalse();
+    }
+
+    private ProtoLogDataSource.TlsState createTlsState(
+            DataSourceConfigOuterClass.DataSourceConfig config) {
+        final ProtoLogDataSource ds =
+                Mockito.spy(new ProtoLogDataSource(() -> {}, () -> {}, () -> {}));
+
+        ProtoInputStream configStream = new ProtoInputStream(config.toByteArray());
+        final ProtoLogDataSource.Instance dsInstance = Mockito.spy(
+                ds.createInstance(configStream, 8));
+        Mockito.doNothing().when(dsInstance).release();
+        final CreateTlsStateArgs mockCreateTlsStateArgs = Mockito.mock(CreateTlsStateArgs.class);
+        Mockito.when(mockCreateTlsStateArgs.getDataSourceInstanceLocked()).thenReturn(dsInstance);
+        return ds.createTlsState(mockCreateTlsStateArgs);
+    }
+}
diff --git a/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java
new file mode 100644
index 0000000..270f595
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java
@@ -0,0 +1,586 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.protolog;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import static java.io.File.createTempFile;
+import static java.nio.file.Files.createTempDirectory;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
+import android.tools.ScenarioBuilder;
+import android.tools.traces.TraceConfig;
+import android.tools.traces.TraceConfigs;
+import android.tools.traces.io.ResultReader;
+import android.tools.traces.io.ResultWriter;
+import android.tools.traces.monitors.PerfettoTraceMonitor;
+import android.tools.traces.protolog.ProtoLogTrace;
+import android.tracing.perfetto.DataSource;
+import android.util.proto.ProtoInputStream;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.protolog.common.IProtoLogGroup;
+import com.android.internal.protolog.common.LogDataType;
+import com.android.internal.protolog.common.LogLevel;
+
+import com.google.common.truth.Truth;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Random;
+
+import perfetto.protos.Protolog;
+import perfetto.protos.ProtologCommon;
+
+/**
+ * Test class for {@link ProtoLogImpl}.
+ */
+@SuppressWarnings("ConstantConditions")
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class PerfettoProtoLogImplTest {
+    private final File mTracingDirectory = createTempDirectory("temp").toFile();
+
+    private final ResultWriter mWriter = new ResultWriter()
+            .forScenario(new ScenarioBuilder()
+                    .forClass(createTempFile("temp", "").getName()).build())
+            .withOutputDir(mTracingDirectory)
+            .setRunComplete();
+
+    private final TraceConfigs mTraceConfig = new TraceConfigs(
+            new TraceConfig(false, true, false),
+            new TraceConfig(false, true, false),
+            new TraceConfig(false, true, false),
+            new TraceConfig(false, true, false)
+    );
+
+    private PerfettoProtoLogImpl mProtoLog;
+    private Protolog.ProtoLogViewerConfig.Builder mViewerConfigBuilder;
+    private File mFile;
+
+    private ProtoLogViewerConfigReader mReader;
+
+    public PerfettoProtoLogImplTest() throws IOException {
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        final Context testContext = getInstrumentation().getContext();
+        mFile = testContext.getFileStreamPath("tracing_test.dat");
+        //noinspection ResultOfMethodCallIgnored
+        mFile.delete();
+
+        mViewerConfigBuilder = Protolog.ProtoLogViewerConfig.newBuilder()
+                .addGroups(
+                        Protolog.ProtoLogViewerConfig.Group.newBuilder()
+                                .setId(1)
+                                .setName(TestProtoLogGroup.TEST_GROUP.toString())
+                                .setTag(TestProtoLogGroup.TEST_GROUP.getTag())
+                ).addMessages(
+                        Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+                                .setMessageId(1)
+                                .setMessage("My Test Debug Log Message %b")
+                                .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_DEBUG)
+                                .setGroupId(1)
+                ).addMessages(
+                        Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+                                .setMessageId(2)
+                                .setMessage("My Test Verbose Log Message %b")
+                                .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_VERBOSE)
+                                .setGroupId(1)
+                ).addMessages(
+                        Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+                                .setMessageId(3)
+                                .setMessage("My Test Warn Log Message %b")
+                                .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_WARN)
+                                .setGroupId(1)
+                ).addMessages(
+                        Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+                                .setMessageId(4)
+                                .setMessage("My Test Error Log Message %b")
+                                .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_ERROR)
+                                .setGroupId(1)
+                ).addMessages(
+                        Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+                                .setMessageId(5)
+                                .setMessage("My Test WTF Log Message %b")
+                                .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_WTF)
+                                .setGroupId(1)
+                );
+
+        ViewerConfigInputStreamProvider viewerConfigInputStreamProvider = Mockito.mock(
+                ViewerConfigInputStreamProvider.class);
+        Mockito.when(viewerConfigInputStreamProvider.getInputStream())
+                .thenAnswer(it -> new ProtoInputStream(mViewerConfigBuilder.build().toByteArray()));
+
+        mReader = Mockito.spy(new ProtoLogViewerConfigReader(viewerConfigInputStreamProvider));
+        mProtoLog = new PerfettoProtoLogImpl(viewerConfigInputStreamProvider, mReader);
+    }
+
+    @After
+    public void tearDown() {
+        if (mFile != null) {
+            //noinspection ResultOfMethodCallIgnored
+            mFile.delete();
+        }
+        ProtoLogImpl.setSingleInstance(null);
+    }
+
+    @Test
+    public void isEnabled_returnsFalseByDefault() {
+        assertFalse(mProtoLog.isProtoEnabled());
+    }
+
+    @Test
+    public void isEnabled_returnsTrueAfterStart() {
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog().build();
+        try {
+            traceMonitor.start();
+            assertTrue(mProtoLog.isProtoEnabled());
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+    }
+
+    @Test
+    public void isEnabled_returnsFalseAfterStop() {
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog().build();
+        try {
+            traceMonitor.start();
+            assertTrue(mProtoLog.isProtoEnabled());
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        assertFalse(mProtoLog.isProtoEnabled());
+    }
+
+    @Test
+    public void defaultMode() throws IOException {
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog(false).build();
+        try {
+            traceMonitor.start();
+            // Shouldn't be logging anything except WTF unless explicitly requested in the group
+            // override.
+            mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig);
+        final ProtoLogTrace protolog = reader.readProtoLogTrace();
+
+        Truth.assertThat(protolog.messages).hasSize(1);
+        Truth.assertThat(protolog.messages.getFirst().getLevel()).isEqualTo(LogLevel.WTF);
+    }
+
+    @Test
+    public void respectsOverrideConfigs_defaultMode() throws IOException {
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog(true,
+                        List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride(
+                                TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.DEBUG, true)))
+                        .build();
+        try {
+            traceMonitor.start();
+            mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig);
+        final ProtoLogTrace protolog = reader.readProtoLogTrace();
+
+        Truth.assertThat(protolog.messages).hasSize(5);
+        Truth.assertThat(protolog.messages.get(0).getLevel()).isEqualTo(LogLevel.DEBUG);
+        Truth.assertThat(protolog.messages.get(1).getLevel()).isEqualTo(LogLevel.VERBOSE);
+        Truth.assertThat(protolog.messages.get(2).getLevel()).isEqualTo(LogLevel.WARN);
+        Truth.assertThat(protolog.messages.get(3).getLevel()).isEqualTo(LogLevel.ERROR);
+        Truth.assertThat(protolog.messages.get(4).getLevel()).isEqualTo(LogLevel.WTF);
+    }
+
+    @Test
+    public void respectsOverrideConfigs_allEnabledMode() throws IOException {
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog(true,
+                        List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride(
+                                TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.WARN, false)))
+                        .build();
+        try {
+            traceMonitor.start();
+            mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig);
+        final ProtoLogTrace protolog = reader.readProtoLogTrace();
+
+        Truth.assertThat(protolog.messages).hasSize(3);
+        Truth.assertThat(protolog.messages.get(0).getLevel()).isEqualTo(LogLevel.WARN);
+        Truth.assertThat(protolog.messages.get(1).getLevel()).isEqualTo(LogLevel.ERROR);
+        Truth.assertThat(protolog.messages.get(2).getLevel()).isEqualTo(LogLevel.WTF);
+    }
+
+    @Test
+    public void respectsAllEnabledMode() throws IOException {
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog(true, List.of())
+                        .build();
+        try {
+            traceMonitor.start();
+            mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig);
+        final ProtoLogTrace protolog = reader.readProtoLogTrace();
+
+        Truth.assertThat(protolog.messages).hasSize(5);
+        Truth.assertThat(protolog.messages.get(0).getLevel()).isEqualTo(LogLevel.DEBUG);
+        Truth.assertThat(protolog.messages.get(1).getLevel()).isEqualTo(LogLevel.VERBOSE);
+        Truth.assertThat(protolog.messages.get(2).getLevel()).isEqualTo(LogLevel.WARN);
+        Truth.assertThat(protolog.messages.get(3).getLevel()).isEqualTo(LogLevel.ERROR);
+        Truth.assertThat(protolog.messages.get(4).getLevel()).isEqualTo(LogLevel.WTF);
+    }
+
+    @Test
+    public void log_logcatEnabledExternalMessage() {
+        when(mReader.getViewerString(anyLong())).thenReturn("test %b %d %% 0x%x %s %f");
+        PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+                new Object[]{true, 10000, 30000, "test", 0.000003});
+
+        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+                LogLevel.INFO),
+                eq("test true 10000 % 0x7530 test 3.0E-6"));
+        verify(mReader).getViewerString(eq(1234L));
+    }
+
+    @Test
+    public void log_logcatEnabledInvalidMessage() {
+        when(mReader.getViewerString(anyLong())).thenReturn("test %b %d %% %x %s %f");
+        PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+                new Object[]{true, 10000, 0.0001, 0.00002, "test"});
+
+        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+                LogLevel.INFO),
+                eq("UNKNOWN MESSAGE (1234) true 10000 1.0E-4 2.0E-5 test"));
+        verify(mReader).getViewerString(eq(1234L));
+    }
+
+    @Test
+    public void log_logcatEnabledInlineMessage() {
+        when(mReader.getViewerString(anyLong())).thenReturn("test %d");
+        PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d",
+                new Object[]{5});
+
+        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+                LogLevel.INFO), eq("test 5"));
+        verify(mReader, never()).getViewerString(anyLong());
+    }
+
+    @Test
+    public void log_logcatEnabledNoMessage() {
+        when(mReader.getViewerString(anyLong())).thenReturn(null);
+        PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+                new Object[]{5});
+
+        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+                LogLevel.INFO), eq("UNKNOWN MESSAGE (1234) 5"));
+        verify(mReader).getViewerString(eq(1234L));
+    }
+
+    @Test
+    public void log_logcatDisabled() {
+        when(mReader.getViewerString(anyLong())).thenReturn("test %d");
+        PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d",
+                new Object[]{5});
+
+        verify(implSpy, never()).passToLogcat(any(), any(), any());
+        verify(mReader, never()).getViewerString(anyLong());
+    }
+
+    @Test
+    public void log_protoEnabled() throws Exception {
+        final long messageHash = addMessageToConfig(
+                ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_INFO,
+                "My test message :: %s, %d, %o, %x, %f, %e, %g, %b");
+
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog().build();
+        long before;
+        long after;
+        try {
+            traceMonitor.start();
+            assertTrue(mProtoLog.isProtoEnabled());
+
+            before = SystemClock.elapsedRealtimeNanos();
+            mProtoLog.log(
+                    LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, messageHash,
+                    0b1110101001010100, null,
+                    new Object[]{"test", 1, 2, 3, 0.4, 0.5, 0.6, true});
+            after = SystemClock.elapsedRealtimeNanos();
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig);
+        final ProtoLogTrace protolog = reader.readProtoLogTrace();
+
+        Truth.assertThat(protolog.messages).hasSize(1);
+        Truth.assertThat(protolog.messages.getFirst().getTimestamp().getElapsedNanos())
+                .isAtLeast(before);
+        Truth.assertThat(protolog.messages.getFirst().getTimestamp().getElapsedNanos())
+                .isAtMost(after);
+        Truth.assertThat(protolog.messages.getFirst().getMessage())
+                .isEqualTo("My test message :: test, 2, 4, 6, 0.400000, 5.000000e-01, 0.6, true");
+    }
+
+    private long addMessageToConfig(ProtologCommon.ProtoLogLevel logLevel, String message) {
+        final long messageId = new Random().nextLong();
+        mViewerConfigBuilder.addMessages(Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+                .setMessageId(messageId)
+                .setMessage(message)
+                .setLevel(logLevel)
+                .setGroupId(1)
+        );
+
+        return messageId;
+    }
+
+    @Test
+    public void log_invalidParamsMask() {
+        final long messageHash = addMessageToConfig(
+                ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_INFO,
+                "My test message :: %s, %d, %f, %b");
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog().build();
+        long before;
+        long after;
+        try {
+            traceMonitor.start();
+            before = SystemClock.elapsedRealtimeNanos();
+            mProtoLog.log(
+                    LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, messageHash,
+                    0b01100100, null,
+                    new Object[]{"test", 1, 0.1, true});
+            after = SystemClock.elapsedRealtimeNanos();
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig);
+        assertThrows(IllegalStateException.class, reader::readProtoLogTrace);
+    }
+
+    @Test
+    public void log_protoDisabled() throws Exception {
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog(false).build();
+        try {
+            traceMonitor.start();
+            mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
+                    0b11, null, new Object[]{true});
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig);
+        final ProtoLogTrace protolog = reader.readProtoLogTrace();
+
+        Truth.assertThat(protolog.messages).isEmpty();
+    }
+
+    @Test
+    public void stackTraceTrimmed() throws IOException {
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog(true,
+                        List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride(
+                                TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.DEBUG, true)))
+                        .build();
+        try {
+            traceMonitor.start();
+
+            ProtoLogImpl.setSingleInstance(mProtoLog);
+            ProtoLogImpl.d(TestProtoLogGroup.TEST_GROUP, 1,
+                    0b11, null, true);
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig);
+        final ProtoLogTrace protolog = reader.readProtoLogTrace();
+
+        Truth.assertThat(protolog.messages).hasSize(1);
+        String stacktrace = protolog.messages.getFirst().getStacktrace();
+        Truth.assertThat(stacktrace)
+                .doesNotContain(PerfettoProtoLogImpl.class.getSimpleName() + ".java");
+        Truth.assertThat(stacktrace).doesNotContain(DataSource.class.getSimpleName() + ".java");
+        Truth.assertThat(stacktrace)
+                .doesNotContain(ProtoLogImpl.class.getSimpleName() + ".java");
+        Truth.assertThat(stacktrace).contains(PerfettoProtoLogImplTest.class.getSimpleName());
+        Truth.assertThat(stacktrace).contains("stackTraceTrimmed");
+    }
+
+    private enum TestProtoLogGroup implements IProtoLogGroup {
+        TEST_GROUP(true, true, false, "TEST_TAG");
+
+        private final boolean mEnabled;
+        private volatile boolean mLogToProto;
+        private volatile boolean mLogToLogcat;
+        private final String mTag;
+
+        /**
+         * @param enabled     set to false to exclude all log statements for this group from
+         *                    compilation,
+         *                    they will not be available in runtime.
+         * @param logToProto  enable binary logging for the group
+         * @param logToLogcat enable text logging for the group
+         * @param tag         name of the source of the logged message
+         */
+        TestProtoLogGroup(boolean enabled, boolean logToProto, boolean logToLogcat, String tag) {
+            this.mEnabled = enabled;
+            this.mLogToProto = logToProto;
+            this.mLogToLogcat = logToLogcat;
+            this.mTag = tag;
+        }
+
+        @Override
+        public boolean isEnabled() {
+            return mEnabled;
+        }
+
+        @Override
+        public boolean isLogToProto() {
+            return mLogToProto;
+        }
+
+        @Override
+        public boolean isLogToLogcat() {
+            return mLogToLogcat;
+        }
+
+        @Override
+        public boolean isLogToAny() {
+            return mLogToLogcat || mLogToProto;
+        }
+
+        @Override
+        public String getTag() {
+            return mTag;
+        }
+
+        @Override
+        public void setLogToProto(boolean logToProto) {
+            this.mLogToProto = logToProto;
+        }
+
+        @Override
+        public void setLogToLogcat(boolean logToLogcat) {
+            this.mLogToLogcat = logToLogcat;
+        }
+
+    }
+}
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
index 7deb8c7..4267c2c 100644
--- a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
+++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
@@ -16,49 +16,23 @@
 
 package com.android.internal.protolog;
 
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.internal.protolog.ProtoLogImpl.PROTOLOG_VERSION;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
 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.content.Context;
-import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
-import android.util.proto.ProtoInputStream;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.protolog.common.IProtoLog;
 import com.android.internal.protolog.common.IProtoLogGroup;
+import com.android.internal.protolog.common.LogLevel;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintWriter;
-import java.util.LinkedList;
 
 /**
  * Test class for {@link ProtoLogImpl}.
@@ -68,336 +42,78 @@
 @Presubmit
 @RunWith(JUnit4.class)
 public class ProtoLogImplTest {
-
-    private static final byte[] MAGIC_HEADER = new byte[]{
-            0x9, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x4c, 0x4f, 0x47
-    };
-
-    private ProtoLogImpl mProtoLog;
-    private File mFile;
-
-    @Mock
-    private ProtoLogViewerConfigReader mReader;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        final Context testContext = getInstrumentation().getContext();
-        mFile = testContext.getFileStreamPath("tracing_test.dat");
-        //noinspection ResultOfMethodCallIgnored
-        mFile.delete();
-        mProtoLog = new ProtoLogImpl(mFile, 1024 * 1024, mReader, 1024);
-    }
-
     @After
     public void tearDown() {
-        if (mFile != null) {
-            //noinspection ResultOfMethodCallIgnored
-            mFile.delete();
-        }
         ProtoLogImpl.setSingleInstance(null);
     }
 
     @Test
-    public void isEnabled_returnsFalseByDefault() {
-        assertFalse(mProtoLog.isProtoEnabled());
-    }
-
-    @Test
-    public void isEnabled_returnsTrueAfterStart() {
-        mProtoLog.startProtoLog(mock(PrintWriter.class));
-        assertTrue(mProtoLog.isProtoEnabled());
-    }
-
-    @Test
-    public void isEnabled_returnsFalseAfterStop() {
-        mProtoLog.startProtoLog(mock(PrintWriter.class));
-        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
-        assertFalse(mProtoLog.isProtoEnabled());
-    }
-
-    @Test
-    public void logFile_startsWithMagicHeader() throws Exception {
-        mProtoLog.startProtoLog(mock(PrintWriter.class));
-        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
-
-        assertTrue("Log file should exist", mFile.exists());
-
-        byte[] header = new byte[MAGIC_HEADER.length];
-        try (InputStream is = new FileInputStream(mFile)) {
-            assertEquals(MAGIC_HEADER.length, is.read(header));
-            assertArrayEquals(MAGIC_HEADER, header);
-        }
-    }
-
-    @Test
     public void getSingleInstance() {
-        ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+        IProtoLog mockedProtoLog = mock(IProtoLog.class);
         ProtoLogImpl.setSingleInstance(mockedProtoLog);
         assertSame(mockedProtoLog, ProtoLogImpl.getSingleInstance());
     }
 
     @Test
     public void d_logCalled() {
-        ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+        IProtoLog mockedProtoLog = mock(IProtoLog.class);
         ProtoLogImpl.setSingleInstance(mockedProtoLog);
         ProtoLogImpl.d(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d");
-        verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.DEBUG), eq(
+        verify(mockedProtoLog).log(eq(LogLevel.DEBUG), eq(
                 TestProtoLogGroup.TEST_GROUP),
-                eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+                eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{}));
     }
 
     @Test
     public void v_logCalled() {
-        ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+        IProtoLog mockedProtoLog = mock(IProtoLog.class);
         ProtoLogImpl.setSingleInstance(mockedProtoLog);
         ProtoLogImpl.v(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d");
-        verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.VERBOSE), eq(
+        verify(mockedProtoLog).log(eq(LogLevel.VERBOSE), eq(
                 TestProtoLogGroup.TEST_GROUP),
-                eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+                eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{}));
     }
 
     @Test
     public void i_logCalled() {
-        ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+        IProtoLog mockedProtoLog = mock(IProtoLog.class);
         ProtoLogImpl.setSingleInstance(mockedProtoLog);
         ProtoLogImpl.i(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d");
-        verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.INFO), eq(
+        verify(mockedProtoLog).log(eq(LogLevel.INFO), eq(
                 TestProtoLogGroup.TEST_GROUP),
-                eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+                eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{}));
     }
 
     @Test
     public void w_logCalled() {
-        ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+        IProtoLog mockedProtoLog = mock(IProtoLog.class);
         ProtoLogImpl.setSingleInstance(mockedProtoLog);
         ProtoLogImpl.w(TestProtoLogGroup.TEST_GROUP, 1234,
                 4321, "test %d");
-        verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.WARN), eq(
+        verify(mockedProtoLog).log(eq(LogLevel.WARN), eq(
                 TestProtoLogGroup.TEST_GROUP),
-                eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+                eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{}));
     }
 
     @Test
     public void e_logCalled() {
-        ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+        IProtoLog mockedProtoLog = mock(IProtoLog.class);
         ProtoLogImpl.setSingleInstance(mockedProtoLog);
         ProtoLogImpl.e(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d");
-        verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.ERROR), eq(
+        verify(mockedProtoLog).log(eq(LogLevel.ERROR), eq(
                 TestProtoLogGroup.TEST_GROUP),
-                eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+                eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{}));
     }
 
     @Test
     public void wtf_logCalled() {
-        ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+        IProtoLog mockedProtoLog = mock(IProtoLog.class);
         ProtoLogImpl.setSingleInstance(mockedProtoLog);
         ProtoLogImpl.wtf(TestProtoLogGroup.TEST_GROUP,
                 1234, 4321, "test %d");
-        verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.WTF), eq(
+        verify(mockedProtoLog).log(eq(LogLevel.WTF), eq(
                 TestProtoLogGroup.TEST_GROUP),
-                eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
-    }
-
-    @Test
-    public void log_logcatEnabledExternalMessage() {
-        when(mReader.getViewerString(anyInt())).thenReturn("test %b %d %% 0x%x %s %f");
-        ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
-        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
-        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
-
-        implSpy.log(
-                ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
-                new Object[]{true, 10000, 30000, "test", 0.000003});
-
-        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
-                ProtoLogImpl.LogLevel.INFO),
-                eq("test true 10000 % 0x7530 test 3.0E-6"));
-        verify(mReader).getViewerString(eq(1234));
-    }
-
-    @Test
-    public void log_logcatEnabledInvalidMessage() {
-        when(mReader.getViewerString(anyInt())).thenReturn("test %b %d %% %x %s %f");
-        ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
-        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
-        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
-
-        implSpy.log(
-                ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
-                new Object[]{true, 10000, 0.0001, 0.00002, "test"});
-
-        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
-                ProtoLogImpl.LogLevel.INFO),
-                eq("UNKNOWN MESSAGE (1234) true 10000 1.0E-4 2.0E-5 test"));
-        verify(mReader).getViewerString(eq(1234));
-    }
-
-    @Test
-    public void log_logcatEnabledInlineMessage() {
-        when(mReader.getViewerString(anyInt())).thenReturn("test %d");
-        ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
-        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
-        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
-
-        implSpy.log(
-                ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d",
-                new Object[]{5});
-
-        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
-                ProtoLogImpl.LogLevel.INFO), eq("test 5"));
-        verify(mReader, never()).getViewerString(anyInt());
-    }
-
-    @Test
-    public void log_logcatEnabledNoMessage() {
-        when(mReader.getViewerString(anyInt())).thenReturn(null);
-        ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
-        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
-        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
-
-        implSpy.log(
-                ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
-                new Object[]{5});
-
-        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
-                ProtoLogImpl.LogLevel.INFO), eq("UNKNOWN MESSAGE (1234) 5"));
-        verify(mReader).getViewerString(eq(1234));
-    }
-
-    @Test
-    public void log_logcatDisabled() {
-        when(mReader.getViewerString(anyInt())).thenReturn("test %d");
-        ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
-        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
-        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
-
-        implSpy.log(
-                ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d",
-                new Object[]{5});
-
-        verify(implSpy, never()).passToLogcat(any(), any(), any());
-        verify(mReader, never()).getViewerString(anyInt());
-    }
-
-    private static class ProtoLogData {
-        Integer mMessageHash = null;
-        Long mElapsedTime = null;
-        LinkedList<String> mStrParams = new LinkedList<>();
-        LinkedList<Long> mSint64Params = new LinkedList<>();
-        LinkedList<Double> mDoubleParams = new LinkedList<>();
-        LinkedList<Boolean> mBooleanParams = new LinkedList<>();
-    }
-
-    private ProtoLogData readProtoLogSingle(ProtoInputStream ip) throws IOException {
-        while (ip.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
-            if (ip.getFieldNumber() == (int) ProtoLogFileProto.VERSION) {
-                assertEquals(PROTOLOG_VERSION, ip.readString(ProtoLogFileProto.VERSION));
-                continue;
-            }
-            if (ip.getFieldNumber() != (int) ProtoLogFileProto.LOG) {
-                continue;
-            }
-            long token = ip.start(ProtoLogFileProto.LOG);
-            ProtoLogData data = new ProtoLogData();
-            while (ip.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
-                switch (ip.getFieldNumber()) {
-                    case (int) ProtoLogMessage.MESSAGE_HASH: {
-                        data.mMessageHash = ip.readInt(ProtoLogMessage.MESSAGE_HASH);
-                        break;
-                    }
-                    case (int) ProtoLogMessage.ELAPSED_REALTIME_NANOS: {
-                        data.mElapsedTime = ip.readLong(ProtoLogMessage.ELAPSED_REALTIME_NANOS);
-                        break;
-                    }
-                    case (int) ProtoLogMessage.STR_PARAMS: {
-                        data.mStrParams.add(ip.readString(ProtoLogMessage.STR_PARAMS));
-                        break;
-                    }
-                    case (int) ProtoLogMessage.SINT64_PARAMS: {
-                        data.mSint64Params.add(ip.readLong(ProtoLogMessage.SINT64_PARAMS));
-                        break;
-                    }
-                    case (int) ProtoLogMessage.DOUBLE_PARAMS: {
-                        data.mDoubleParams.add(ip.readDouble(ProtoLogMessage.DOUBLE_PARAMS));
-                        break;
-                    }
-                    case (int) ProtoLogMessage.BOOLEAN_PARAMS: {
-                        data.mBooleanParams.add(ip.readBoolean(ProtoLogMessage.BOOLEAN_PARAMS));
-                        break;
-                    }
-                }
-            }
-            ip.end(token);
-            return data;
-        }
-        return null;
-    }
-
-    @Test
-    public void log_protoEnabled() throws Exception {
-        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
-        TestProtoLogGroup.TEST_GROUP.setLogToProto(true);
-        mProtoLog.startProtoLog(mock(PrintWriter.class));
-        long before = SystemClock.elapsedRealtimeNanos();
-        mProtoLog.log(
-                ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
-                0b1110101001010100, null,
-                new Object[]{"test", 1, 2, 3, 0.4, 0.5, 0.6, true});
-        long after = SystemClock.elapsedRealtimeNanos();
-        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
-        try (InputStream is = new FileInputStream(mFile)) {
-            ProtoInputStream ip = new ProtoInputStream(is);
-            ProtoLogData data = readProtoLogSingle(ip);
-            assertNotNull(data);
-            assertEquals(1234, data.mMessageHash.longValue());
-            assertTrue(before <= data.mElapsedTime && data.mElapsedTime <= after);
-            assertArrayEquals(new String[]{"test"}, data.mStrParams.toArray());
-            assertArrayEquals(new Long[]{1L, 2L, 3L}, data.mSint64Params.toArray());
-            assertArrayEquals(new Double[]{0.4, 0.5, 0.6}, data.mDoubleParams.toArray());
-            assertArrayEquals(new Boolean[]{true}, data.mBooleanParams.toArray());
-        }
-    }
-
-    @Test
-    public void log_invalidParamsMask() throws Exception {
-        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
-        TestProtoLogGroup.TEST_GROUP.setLogToProto(true);
-        mProtoLog.startProtoLog(mock(PrintWriter.class));
-        long before = SystemClock.elapsedRealtimeNanos();
-        mProtoLog.log(
-                ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
-                0b01100100, null,
-                new Object[]{"test", 1, 0.1, true});
-        long after = SystemClock.elapsedRealtimeNanos();
-        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
-        try (InputStream is = new FileInputStream(mFile)) {
-            ProtoInputStream ip = new ProtoInputStream(is);
-            ProtoLogData data = readProtoLogSingle(ip);
-            assertNotNull(data);
-            assertEquals(1234, data.mMessageHash.longValue());
-            assertTrue(before <= data.mElapsedTime && data.mElapsedTime <= after);
-            assertArrayEquals(new String[]{"test", "(INVALID PARAMS_MASK) true"},
-                    data.mStrParams.toArray());
-            assertArrayEquals(new Long[]{1L}, data.mSint64Params.toArray());
-            assertArrayEquals(new Double[]{0.1}, data.mDoubleParams.toArray());
-            assertArrayEquals(new Boolean[]{}, data.mBooleanParams.toArray());
-        }
-    }
-
-    @Test
-    public void log_protoDisabled() throws Exception {
-        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
-        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
-        mProtoLog.startProtoLog(mock(PrintWriter.class));
-        mProtoLog.log(ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
-                0b11, null, new Object[]{true});
-        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
-        try (InputStream is = new FileInputStream(mFile)) {
-            ProtoInputStream ip = new ProtoInputStream(is);
-            ProtoLogData data = readProtoLogSingle(ip);
-            assertNull(data);
-        }
+                eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{}));
     }
 
     private enum TestProtoLogGroup implements IProtoLogGroup {
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
index ae50216..dbd85d3 100644
--- a/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
+++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
@@ -72,8 +72,8 @@
             + "}\n";
 
 
-    private ProtoLogViewerConfigReader
-            mConfig = new ProtoLogViewerConfigReader();
+    private LegacyProtoLogViewerConfigReader
+            mConfig = new LegacyProtoLogViewerConfigReader();
     private File mTestViewerConfig;
 
     @Before
@@ -98,7 +98,7 @@
 
     @Test
     public void loadViewerConfig() {
-        mConfig.loadViewerConfig(null, mTestViewerConfig.getAbsolutePath());
+        mConfig.loadViewerConfig(msg -> {}, mTestViewerConfig.getAbsolutePath());
         assertEquals("Test completed successfully: %b", mConfig.getViewerString(70933285));
         assertEquals("Test 2", mConfig.getViewerString(1352021864));
         assertEquals("Window %s is already added", mConfig.getViewerString(409412266));
@@ -107,7 +107,7 @@
 
     @Test
     public void loadViewerConfig_invalidFile() {
-        mConfig.loadViewerConfig(null, "/tmp/unknown/file/does/not/exist");
+        mConfig.loadViewerConfig(msg -> {}, "/tmp/unknown/file/does/not/exist");
         // No exception is thrown.
         assertNull(mConfig.getViewerString(1));
     }
diff --git a/tests/SurfaceComposition/Android.bp b/tests/SurfaceComposition/Android.bp
index f5aba8f5..a02662f 100644
--- a/tests/SurfaceComposition/Android.bp
+++ b/tests/SurfaceComposition/Android.bp
@@ -32,7 +32,10 @@
         enabled: false,
     },
     srcs: ["src/**/*.java"],
-    static_libs: ["junit"],
+    static_libs: [
+        "junit",
+        "androidx.test.rules",
+    ],
     libs: [
         "android.test.runner.stubs",
         "android.test.base.stubs",
diff --git a/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionTest.java b/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionTest.java
index 261ea2e..f82585c 100644
--- a/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionTest.java
+++ b/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionTest.java
@@ -22,9 +22,10 @@
 import android.surfacecomposition.SurfaceCompositionMeasuringActivity.AllocationScore;
 import android.surfacecomposition.SurfaceCompositionMeasuringActivity.CompositorScore;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
+import androidx.test.filters.SmallTest;
+
 public class SurfaceCompositionTest extends
         ActivityInstrumentationTestCase2<SurfaceCompositionMeasuringActivity> {
     private final static String TAG = "SurfaceCompositionTest";
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt
index 97398dc..c258347 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt
@@ -15,7 +15,7 @@
  */
 package com.android.test
 
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
+import android.tools.flicker.subject.layers.LayersTraceSubject
 import junit.framework.Assert.assertEquals
 import junit.framework.Assert.assertTrue
 import org.junit.Test
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt
index 0cc18d6..0e70df4 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt
@@ -16,7 +16,7 @@
 package com.android.test
 
 import android.graphics.Point
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
+import android.tools.flicker.subject.layers.LayersTraceSubject
 import com.android.test.SurfaceViewBufferTestBase.Companion.ScalingMode
 import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
 import junit.framework.Assert.assertEquals
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt
index 6f4d11c..8502474 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt
@@ -19,7 +19,7 @@
 import android.graphics.Point
 import android.graphics.Rect
 import android.os.SystemClock
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
+import android.tools.flicker.subject.layers.LayersTraceSubject
 import com.android.test.SurfaceViewBufferTestBase.Companion.ScalingMode
 import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
 import junit.framework.Assert.assertEquals
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt
index 1de965e..ad8b35e 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt
@@ -16,7 +16,7 @@
 package com.android.test
 
 import android.graphics.Point
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
+import android.tools.flicker.subject.layers.LayersTraceSubject
 import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
 import junit.framework.Assert.assertEquals
 import org.junit.Assert
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt
index 4c5224a..b2ceb40 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt
@@ -17,7 +17,7 @@
 
 import android.graphics.Color
 import android.graphics.Rect
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
+import android.tools.flicker.subject.layers.LayersTraceSubject
 import junit.framework.Assert.assertEquals
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
index b03b733..6e77796 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
@@ -21,9 +21,9 @@
 import android.graphics.Rect
 import android.util.Log
 import androidx.test.ext.junit.rules.ActivityScenarioRule
-import android.tools.common.traces.surfaceflinger.LayersTrace
-import android.tools.device.traces.monitors.withSFTracing
-import android.tools.device.traces.monitors.PerfettoTraceMonitor
+import android.tools.traces.surfaceflinger.LayersTrace
+import android.tools.traces.monitors.withSFTracing
+import android.tools.traces.monitors.PerfettoTraceMonitor
 import junit.framework.Assert
 import org.junit.After
 import org.junit.Before
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt
index 1770e32..e0b1809 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt
@@ -18,8 +18,8 @@
 import android.app.Instrumentation
 import android.graphics.Point
 import android.provider.Settings
-import android.tools.common.datatypes.Size
-import android.tools.common.flicker.subject.layers.LayerSubject
+import android.tools.datatypes.Size
+import android.tools.flicker.subject.layers.LayerSubject
 import androidx.test.InstrumentationRegistry
 import org.junit.After
 import org.junit.Before
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
index 2c7905d..e76a399 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
@@ -20,9 +20,9 @@
 import androidx.test.ext.junit.rules.ActivityScenarioRule
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.runner.AndroidJUnit4
-import android.tools.common.datatypes.Size
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.device.traces.monitors.withSFTracing
+import android.tools.datatypes.Size
+import android.tools.flicker.subject.layers.LayersTraceSubject
+import android.tools.traces.monitors.withSFTracing
 import org.junit.After
 import org.junit.Before
 import org.junit.FixMethodOrder
diff --git a/tests/permission/Android.bp b/tests/permission/Android.bp
index d06809b..b02f410 100644
--- a/tests/permission/Android.bp
+++ b/tests/permission/Android.bp
@@ -20,6 +20,7 @@
         "androidx.test.runner",
         "junit",
         "platform-test-annotations",
+        "androidx.test.rules",
     ],
     platform_apis: true,
     test_suites: ["device-tests"],
diff --git a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
index 5fb23b0a..99ca9c08 100644
--- a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
@@ -21,7 +21,8 @@
 import android.app.IActivityManager;
 import android.content.res.Configuration;
 import android.os.RemoteException;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/tests/permission/src/com/android/framework/permission/tests/PmPermissionsTests.java b/tests/permission/src/com/android/framework/permission/tests/PmPermissionsTests.java
index 299d8d0..0c9d447 100644
--- a/tests/permission/src/com/android/framework/permission/tests/PmPermissionsTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/PmPermissionsTests.java
@@ -19,7 +19,8 @@
 import android.app.PackageInstallObserver;
 import android.content.pm.PackageManager;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 /**
  * Verify PackageManager api's that require specific permissions.
diff --git a/tests/permission/src/com/android/framework/permission/tests/SmsManagerPermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/SmsManagerPermissionTest.java
index 4172743..2fa0b21 100644
--- a/tests/permission/src/com/android/framework/permission/tests/SmsManagerPermissionTest.java
+++ b/tests/permission/src/com/android/framework/permission/tests/SmsManagerPermissionTest.java
@@ -18,7 +18,8 @@
 
 import android.telephony.SmsManager;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import java.util.ArrayList;
 
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 330bc84..e67fd67 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -23,9 +23,10 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.IWindowManager;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
 /**
diff --git a/tests/testables/tests/src/android/testing/TestableLooperTest.java b/tests/testables/tests/src/android/testing/TestableLooperTest.java
index a02eb6b..fd5c4ca 100644
--- a/tests/testables/tests/src/android/testing/TestableLooperTest.java
+++ b/tests/testables/tests/src/android/testing/TestableLooperTest.java
@@ -30,10 +30,11 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.TestableLooper.MessageHandler;
 import android.testing.TestableLooper.RunWithLooper;
 
+import androidx.test.filters.SmallTest;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/tests/testables/tests/src/android/testing/TestableResourcesTest.java b/tests/testables/tests/src/android/testing/TestableResourcesTest.java
index dd4325c..7791694 100644
--- a/tests/testables/tests/src/android/testing/TestableResourcesTest.java
+++ b/tests/testables/tests/src/android/testing/TestableResourcesTest.java
@@ -21,9 +21,9 @@
 import static org.junit.Assert.fail;
 
 import android.content.res.Resources;
-import android.test.suitebuilder.annotation.SmallTest;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 
 import com.android.testables.R;
 
diff --git a/tests/testables/tests/src/android/testing/TestableSettingsProviderTest.java b/tests/testables/tests/src/android/testing/TestableSettingsProviderTest.java
index 0333d51..f3f429a 100644
--- a/tests/testables/tests/src/android/testing/TestableSettingsProviderTest.java
+++ b/tests/testables/tests/src/android/testing/TestableSettingsProviderTest.java
@@ -20,9 +20,9 @@
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
-import android.test.suitebuilder.annotation.SmallTest;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
diff --git a/tests/utils/testutils/tests/Android.bp b/tests/utils/testutils/tests/Android.bp
index b901b18..8104280 100644
--- a/tests/utils/testutils/tests/Android.bp
+++ b/tests/utils/testutils/tests/Android.bp
@@ -31,6 +31,7 @@
         "androidx.test.runner",
         "mockito-target-minus-junit4",
         "frameworks-base-testutils",
+        "androidx.test.rules",
     ],
 
     libs: [
diff --git a/tests/utils/testutils/tests/src/android/os/test/TestLooperTest.java b/tests/utils/testutils/tests/src/android/os/test/TestLooperTest.java
index c72e20c..6205b98 100644
--- a/tests/utils/testutils/tests/src/android/os/test/TestLooperTest.java
+++ b/tests/utils/testutils/tests/src/android/os/test/TestLooperTest.java
@@ -28,7 +28,8 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index b054a57..b4e2758 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -15,12 +15,7 @@
 //
 
 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"],
+    default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
 toolSources = [
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
deleted file mode 100644
index 15ae2ba..0000000
--- a/tools/aapt2/Android.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-include $(CLEAR_VARS)
-aapt2_results := ./out/soong/.intermediates/frameworks/base/tools/aapt2/aapt2_results
-$(call declare-1p-target,$(aapt2_results))
-aapt2_results :=
diff --git a/tools/hoststubgen/TEST_MAPPING b/tools/hoststubgen/TEST_MAPPING
index eca258c..b5d5b5f 100644
--- a/tools/hoststubgen/TEST_MAPPING
+++ b/tools/hoststubgen/TEST_MAPPING
@@ -1,6 +1,7 @@
 {
   "presubmit": [
-    { "name": "tiny-framework-dump-test" },
+    // TODO(b/326897452): Reenable after JDK 21 switch.
+    // { "name": "tiny-framework-dump-test" },
     { "name": "hoststubgentest" },
     { "name": "hoststubgen-invoke-test" }
   ],
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/SubclassFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/SubclassFilter.kt
index 83e09bf..fd7474b 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/SubclassFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/SubclassFilter.kt
@@ -20,7 +20,7 @@
 
 /**
  * Filter to apply a policy to classes extending or implementing a class,
- * either directly or indirectly. (with a breadth first search.)
+ * either directly or indirectly.
  *
  * The policy won't apply to the super class itself.
  */
@@ -42,7 +42,7 @@
     }
 
     /**
-     * Find a policy for a class with a breadth-first search.
+     * Find a policy for a class.
      */
     private fun findPolicyForClass(className: String): FilterPolicyWithReason? {
         val cn = classes.findClass(className) ?: return null
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
index cee29dc..1dec6ab 100755
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
@@ -46,6 +46,7 @@
 class TestWithGoldenOutput(unittest.TestCase):
 
     # Test to check the generated jar files to the golden output.
+    @unittest.skip("Disabled until JDK 21 is merged and the golden files updated")
     def test_compare_to_golden(self):
         files = os.listdir(GOLDEN_DIR)
         files.sort()
diff --git a/tools/protologtool/Android.bp b/tools/protologtool/Android.bp
index 46745e9..8fbc3e8 100644
--- a/tools/protologtool/Android.bp
+++ b/tools/protologtool/Android.bp
@@ -11,12 +11,13 @@
     name: "protologtool-lib",
     srcs: [
         "src/com/android/protolog/tool/**/*.kt",
-        ":protolog-common-no-android-src",
+        ":protolog-common-src",
     ],
     static_libs: [
         "javaparser",
         "platformprotos",
         "jsonlib",
+        "perfetto_trace-full",
     ],
 }
 
@@ -42,5 +43,6 @@
         "junit",
         "mockito",
         "objenesis",
+        "truth",
     ],
 }
diff --git a/tools/protologtool/README.md b/tools/protologtool/README.md
index ba63957..24a4861 100644
--- a/tools/protologtool/README.md
+++ b/tools/protologtool/README.md
@@ -8,11 +8,13 @@
 
 ### Code transformation
 
-Command: `protologtool transform-protolog-calls 
-    --protolog-class <protolog class name> 
-    --protolog-impl-class <protolog implementation class name>
+Command: `protologtool transform-protolog-calls
+    --protolog-class <protolog class name>
     --loggroups-class <protolog groups class name>
     --loggroups-jar <config jar path>
+    --viewer-config-file-path <protobuf viewer config file path>
+    --legacy-viewer-config-file-path <legacy json.gz viewer config file path>
+    --legacy-output-file-path <.winscope file path to write the legacy trace to>
     --output-srcjar <output.srcjar>
     [<input.java>]`
 
@@ -44,10 +46,11 @@
 ### Viewer config generation
 
 Command: `generate-viewer-config
-    --protolog-class <protolog class name> 
+    --protolog-class <protolog class name>
     --loggroups-class <protolog groups class name>
     --loggroups-jar <config jar path>
-    --viewer-conf <viewer.json>
+    --viewer-config-type <proto|json>
+    --viewer-config <viewer.json>
     [<input.java>]`
 
 This command is similar in it's syntax to the previous one, only instead of creating a processed source jar
@@ -74,7 +77,7 @@
 
 ### Binary log viewing
 
-Command: `read-log --viewer-conf <viewer.json> <wm_log.pb>`
+Command: `read-log --viewer-config <viewer.json> <wm_log.pb>`
 
 Reads the binary ProtoLog log file and outputs a human-readable LogCat-like text log.
 
diff --git a/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt b/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt
index 07c6fd3..3d1dec2 100644
--- a/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt
@@ -22,15 +22,21 @@
 import com.github.javaparser.ast.expr.BinaryExpr
 import com.github.javaparser.ast.expr.Expression
 import com.github.javaparser.ast.expr.StringLiteralExpr
+import java.util.UUID
 
 object CodeUtils {
     /**
      * Returns a stable hash of a string.
      * We reimplement String::hashCode() for readability reasons.
      */
-    fun hash(position: String, messageString: String, logLevel: LogLevel, logGroup: LogGroup): Int {
-        return (position + messageString + logLevel.name + logGroup.name)
-                .map { c -> c.code }.reduce { h, c -> h * 31 + c }
+    fun hash(
+        position: String,
+        messageString: String,
+        logLevel: LogLevel,
+        logGroup: LogGroup
+    ): Long {
+        val fullStringIdentifier = position + messageString + logLevel.name + logGroup.name
+        return UUID.nameUUIDFromBytes(fullStringIdentifier.toByteArray()).mostSignificantBits
     }
 
     fun checkWildcardStaticImported(code: CompilationUnit, className: String, fileName: String) {
diff --git a/tools/protologtool/src/com/android/protolog/tool/CommandOptions.kt b/tools/protologtool/src/com/android/protolog/tool/CommandOptions.kt
index bfbbf7a..a359155 100644
--- a/tools/protologtool/src/com/android/protolog/tool/CommandOptions.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/CommandOptions.kt
@@ -26,32 +26,35 @@
         private val commands = setOf(TRANSFORM_CALLS_CMD, GENERATE_CONFIG_CMD, READ_LOG_CMD)
 
         private const val PROTOLOG_CLASS_PARAM = "--protolog-class"
-        private const val PROTOLOGIMPL_CLASS_PARAM = "--protolog-impl-class"
-        private const val PROTOLOGCACHE_CLASS_PARAM = "--protolog-cache-class"
         private const val PROTOLOGGROUP_CLASS_PARAM = "--loggroups-class"
         private const val PROTOLOGGROUP_JAR_PARAM = "--loggroups-jar"
-        private const val VIEWER_CONFIG_JSON_PARAM = "--viewer-conf"
+        private const val VIEWER_CONFIG_PARAM = "--viewer-config"
+        private const val VIEWER_CONFIG_TYPE_PARAM = "--viewer-config-type"
         private const val OUTPUT_SOURCE_JAR_PARAM = "--output-srcjar"
-        private val parameters = setOf(PROTOLOG_CLASS_PARAM, PROTOLOGIMPL_CLASS_PARAM,
-                PROTOLOGCACHE_CLASS_PARAM, PROTOLOGGROUP_CLASS_PARAM, PROTOLOGGROUP_JAR_PARAM,
-                VIEWER_CONFIG_JSON_PARAM, OUTPUT_SOURCE_JAR_PARAM)
+        private const val VIEWER_CONFIG_FILE_PATH_PARAM = "--viewer-config-file-path"
+        // TODO(b/324128613): Remove these legacy options once we fully flip the Perfetto protolog flag
+        private const val LEGACY_VIEWER_CONFIG_FILE_PATH_PARAM = "--legacy-viewer-config-file-path"
+        private const val LEGACY_OUTPUT_FILE_PATH = "--legacy-output-file-path"
+        private val parameters = setOf(PROTOLOG_CLASS_PARAM, PROTOLOGGROUP_CLASS_PARAM,
+            PROTOLOGGROUP_JAR_PARAM, VIEWER_CONFIG_PARAM, VIEWER_CONFIG_TYPE_PARAM,
+            OUTPUT_SOURCE_JAR_PARAM, VIEWER_CONFIG_FILE_PATH_PARAM,
+            LEGACY_VIEWER_CONFIG_FILE_PATH_PARAM, LEGACY_OUTPUT_FILE_PATH)
 
         val USAGE = """
             Usage: ${Constants.NAME} <command> [<args>]
             Available commands:
 
-            $TRANSFORM_CALLS_CMD $PROTOLOG_CLASS_PARAM <class name> $PROTOLOGIMPL_CLASS_PARAM
-                <class name> $PROTOLOGCACHE_CLASS_PARAM
-                <class name> $PROTOLOGGROUP_CLASS_PARAM <class name> $PROTOLOGGROUP_JAR_PARAM
-                <config.jar> $OUTPUT_SOURCE_JAR_PARAM <output.srcjar> [<input.java>]
+            $TRANSFORM_CALLS_CMD $PROTOLOG_CLASS_PARAM <class name>
+                $PROTOLOGGROUP_CLASS_PARAM <class name> $PROTOLOGGROUP_JAR_PARAM <config.jar>
+                $OUTPUT_SOURCE_JAR_PARAM <output.srcjar> [<input.java>]
             - processes java files replacing stub calls with logging code.
 
-            $GENERATE_CONFIG_CMD $PROTOLOG_CLASS_PARAM <class name> $PROTOLOGGROUP_CLASS_PARAM
-                <class name> $PROTOLOGGROUP_JAR_PARAM <config.jar> $VIEWER_CONFIG_JSON_PARAM
-                <viewer.json> [<input.java>]
+            $GENERATE_CONFIG_CMD $PROTOLOG_CLASS_PARAM <class name>
+                $PROTOLOGGROUP_CLASS_PARAM <class name> $PROTOLOGGROUP_JAR_PARAM <config.jar>
+                $VIEWER_CONFIG_PARAM <viewer.json|viewer.pb> [<input.java>]
             - creates viewer config file from given java files.
 
-            $READ_LOG_CMD $VIEWER_CONFIG_JSON_PARAM <viewer.json> <wm_log.pb>
+            $READ_LOG_CMD $VIEWER_CONFIG_PARAM <viewer.json|viewer.pb> <wm_log.pb>
             - translates a binary log to a readable format.
         """.trimIndent()
 
@@ -69,6 +72,13 @@
             return params.getValue(paramName)
         }
 
+        private fun getOptionalParam(paramName: String, params: Map<String, String>): String? {
+            if (!params.containsKey(paramName)) {
+                return null
+            }
+            return params.getValue(paramName)
+        }
+
         private fun validateNotSpecified(paramName: String, params: Map<String, String>): String {
             if (params.containsKey(paramName)) {
                 throw InvalidCommandException("Unsupported param $paramName")
@@ -90,9 +100,43 @@
             return name
         }
 
-        private fun validateJSONName(name: String): String {
-            if (!name.endsWith(".json")) {
-                throw InvalidCommandException("Json file required, got $name instead")
+        private fun validateViewerConfigFilePath(name: String): String {
+            if (!name.endsWith(".pb")) {
+                throw InvalidCommandException("Proto file (ending with .pb) required, " +
+                        "got $name instead")
+            }
+            return name
+        }
+
+        private fun validateLegacyViewerConfigFilePath(name: String): String {
+            if (!name.endsWith(".json.gz")) {
+                throw InvalidCommandException("GZiped Json file (ending with .json.gz) required, " +
+                        "got $name instead")
+            }
+            return name
+        }
+
+        private fun validateOutputFilePath(name: String): String {
+            if (!name.endsWith(".winscope")) {
+                throw InvalidCommandException("Winscope file (ending with .winscope) required, " +
+                        "got $name instead")
+            }
+            return name
+        }
+
+        private fun validateConfigFileName(name: String): String {
+            if (!name.endsWith(".json") && !name.endsWith(".pb")) {
+                throw InvalidCommandException("Json file (ending with .json) or proto file " +
+                        "(ending with .pb) required, got $name instead")
+            }
+            return name
+        }
+
+        private fun validateConfigType(name: String): String {
+            val validType = listOf("json", "proto")
+            if (!validType.contains(name)) {
+                throw InvalidCommandException("Unexpected config file type. " +
+                        "Expected on of [${validType.joinToString()}], but got $name")
             }
             return name
         }
@@ -102,8 +146,8 @@
                 throw InvalidCommandException("No java source input files")
             }
             list.forEach { name ->
-                if (!name.endsWith(".java")) {
-                    throw InvalidCommandException("Not a java source file $name")
+                if (!name.endsWith(".java") && !name.endsWith(".kt")) {
+                    throw InvalidCommandException("Not a java or kotlin source file $name")
                 }
             }
             return list
@@ -122,12 +166,14 @@
 
     val protoLogClassNameArg: String
     val protoLogGroupsClassNameArg: String
-    val protoLogImplClassNameArg: String
-    val protoLogCacheClassNameArg: String
     val protoLogGroupsJarArg: String
-    val viewerConfigJsonArg: String
+    val viewerConfigFileNameArg: String
+    val viewerConfigTypeArg: String
     val outputSourceJarArg: String
     val logProtofileArg: String
+    val viewerConfigFilePathArg: String
+    val legacyViewerConfigFilePathArg: String?
+    val legacyOutputFilePath: String?
     val javaSourceArgs: List<String>
     val command: String
 
@@ -169,38 +215,55 @@
         when (command) {
             TRANSFORM_CALLS_CMD -> {
                 protoLogClassNameArg = validateClassName(getParam(PROTOLOG_CLASS_PARAM, params))
-                protoLogGroupsClassNameArg = validateClassName(getParam(PROTOLOGGROUP_CLASS_PARAM,
-                        params))
-                protoLogImplClassNameArg = validateClassName(getParam(PROTOLOGIMPL_CLASS_PARAM,
-                        params))
-                protoLogCacheClassNameArg = validateClassName(getParam(PROTOLOGCACHE_CLASS_PARAM,
-                        params))
+                protoLogGroupsClassNameArg =
+                    validateClassName(getParam(PROTOLOGGROUP_CLASS_PARAM, params))
                 protoLogGroupsJarArg = validateJarName(getParam(PROTOLOGGROUP_JAR_PARAM, params))
-                viewerConfigJsonArg = validateNotSpecified(VIEWER_CONFIG_JSON_PARAM, params)
+                viewerConfigFileNameArg = validateNotSpecified(VIEWER_CONFIG_PARAM, params)
+                viewerConfigTypeArg = validateNotSpecified(VIEWER_CONFIG_TYPE_PARAM, params)
                 outputSourceJarArg = validateSrcJarName(getParam(OUTPUT_SOURCE_JAR_PARAM, params))
+                viewerConfigFilePathArg = validateViewerConfigFilePath(
+                    getParam(VIEWER_CONFIG_FILE_PATH_PARAM, params))
+                legacyViewerConfigFilePathArg =
+                    getOptionalParam(LEGACY_VIEWER_CONFIG_FILE_PATH_PARAM, params)?.let {
+                        validateLegacyViewerConfigFilePath(it)
+                    }
+                legacyOutputFilePath =
+                    getOptionalParam(LEGACY_OUTPUT_FILE_PATH, params)?.let {
+                        validateOutputFilePath(it)
+                    }
                 javaSourceArgs = validateJavaInputList(inputFiles)
                 logProtofileArg = ""
             }
             GENERATE_CONFIG_CMD -> {
                 protoLogClassNameArg = validateClassName(getParam(PROTOLOG_CLASS_PARAM, params))
-                protoLogGroupsClassNameArg = validateClassName(getParam(PROTOLOGGROUP_CLASS_PARAM,
-                        params))
-                protoLogImplClassNameArg = validateNotSpecified(PROTOLOGIMPL_CLASS_PARAM, params)
-                protoLogCacheClassNameArg = validateNotSpecified(PROTOLOGCACHE_CLASS_PARAM, params)
+                protoLogGroupsClassNameArg =
+                    validateClassName(getParam(PROTOLOGGROUP_CLASS_PARAM, params))
                 protoLogGroupsJarArg = validateJarName(getParam(PROTOLOGGROUP_JAR_PARAM, params))
-                viewerConfigJsonArg = validateJSONName(getParam(VIEWER_CONFIG_JSON_PARAM, params))
+                viewerConfigFileNameArg =
+                    validateConfigFileName(getParam(VIEWER_CONFIG_PARAM, params))
+                viewerConfigTypeArg = validateConfigType(getParam(VIEWER_CONFIG_TYPE_PARAM, params))
                 outputSourceJarArg = validateNotSpecified(OUTPUT_SOURCE_JAR_PARAM, params)
+                viewerConfigFilePathArg =
+                    validateNotSpecified(VIEWER_CONFIG_FILE_PATH_PARAM, params)
+                legacyViewerConfigFilePathArg =
+                    validateNotSpecified(LEGACY_VIEWER_CONFIG_FILE_PATH_PARAM, params)
+                legacyOutputFilePath = validateNotSpecified(LEGACY_OUTPUT_FILE_PATH, params)
                 javaSourceArgs = validateJavaInputList(inputFiles)
                 logProtofileArg = ""
             }
             READ_LOG_CMD -> {
                 protoLogClassNameArg = validateNotSpecified(PROTOLOG_CLASS_PARAM, params)
                 protoLogGroupsClassNameArg = validateNotSpecified(PROTOLOGGROUP_CLASS_PARAM, params)
-                protoLogImplClassNameArg = validateNotSpecified(PROTOLOGIMPL_CLASS_PARAM, params)
-                protoLogCacheClassNameArg = validateNotSpecified(PROTOLOGCACHE_CLASS_PARAM, params)
                 protoLogGroupsJarArg = validateNotSpecified(PROTOLOGGROUP_JAR_PARAM, params)
-                viewerConfigJsonArg = validateJSONName(getParam(VIEWER_CONFIG_JSON_PARAM, params))
+                viewerConfigFileNameArg =
+                    validateConfigFileName(getParam(VIEWER_CONFIG_PARAM, params))
+                viewerConfigTypeArg = validateNotSpecified(VIEWER_CONFIG_TYPE_PARAM, params)
                 outputSourceJarArg = validateNotSpecified(OUTPUT_SOURCE_JAR_PARAM, params)
+                viewerConfigFilePathArg =
+                    validateNotSpecified(VIEWER_CONFIG_FILE_PATH_PARAM, params)
+                legacyViewerConfigFilePathArg =
+                    validateNotSpecified(LEGACY_VIEWER_CONFIG_FILE_PATH_PARAM, params)
+                legacyOutputFilePath = validateNotSpecified(LEGACY_OUTPUT_FILE_PATH, params)
                 javaSourceArgs = listOf()
                 logProtofileArg = validateLogInputList(inputFiles)
             }
diff --git a/tools/protologtool/src/com/android/protolog/tool/Constants.kt b/tools/protologtool/src/com/android/protolog/tool/Constants.kt
index aa3e00f..4a93de9 100644
--- a/tools/protologtool/src/com/android/protolog/tool/Constants.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/Constants.kt
@@ -18,7 +18,7 @@
 
 object Constants {
         const val NAME = "protologtool"
-        const val VERSION = "1.0.0"
+        const val VERSION = "2.0.0"
         const val IS_ENABLED_METHOD = "isEnabled"
         const val ENUM_VALUES_METHOD = "values"
 }
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt b/tools/protologtool/src/com/android/protolog/tool/MethodCallVisitor.kt
similarity index 78%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
copy to tools/protologtool/src/com/android/protolog/tool/MethodCallVisitor.kt
index 8ad0a08..fda6351 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/MethodCallVisitor.kt
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.systemui.volume.panel.component.mediaoutput
+package com.android.protolog.tool
 
-import dagger.Module
+import com.github.javaparser.ast.expr.MethodCallExpr
 
-@Module interface MediaOutputModule
+interface MethodCallVisitor {
+    fun processCall(call: MethodCallExpr)
+}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt
index 9a76a6f..47724b7 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,115 +16,13 @@
 
 package com.android.protolog.tool
 
-import com.android.internal.protolog.common.LogLevel
 import com.github.javaparser.ast.CompilationUnit
-import com.github.javaparser.ast.Node
-import com.github.javaparser.ast.expr.Expression
-import com.github.javaparser.ast.expr.FieldAccessExpr
-import com.github.javaparser.ast.expr.MethodCallExpr
-import com.github.javaparser.ast.expr.NameExpr
 
-/**
- * Helper class for visiting all ProtoLog calls.
- * For every valid call in the given {@code CompilationUnit} a {@code ProtoLogCallVisitor} callback
- * is executed.
- */
-open class ProtoLogCallProcessor(
-    private val protoLogClassName: String,
-    private val protoLogGroupClassName: String,
-    private val groupMap: Map<String, LogGroup>
-) {
-    private val protoLogSimpleClassName = protoLogClassName.substringAfterLast('.')
-    private val protoLogGroupSimpleClassName = protoLogGroupClassName.substringAfterLast('.')
-
-    private fun getLogGroupName(
-        expr: Expression,
-        isClassImported: Boolean,
-        staticImports: Set<String>,
+interface ProtoLogCallProcessor {
+    fun process(
+        code: CompilationUnit,
+        logCallVisitor: ProtoLogCallVisitor?,
+        otherCallVisitor: MethodCallVisitor?,
         fileName: String
-    ): String {
-        val context = ParsingContext(fileName, expr)
-        return when (expr) {
-            is NameExpr -> when {
-                expr.nameAsString in staticImports -> expr.nameAsString
-                else ->
-                    throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr",
-                            context)
-            }
-            is FieldAccessExpr -> when {
-                expr.scope.toString() == protoLogGroupClassName
-                        || isClassImported &&
-                        expr.scope.toString() == protoLogGroupSimpleClassName -> expr.nameAsString
-                else ->
-                    throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr",
-                            context)
-            }
-            else -> throw InvalidProtoLogCallException("Invalid group argument " +
-                    "- must be ProtoLogGroup enum member reference: $expr", context)
-        }
-    }
-
-    private fun isProtoCall(
-        call: MethodCallExpr,
-        isLogClassImported: Boolean,
-        staticLogImports: Collection<String>
-    ): Boolean {
-        return call.scope.isPresent && call.scope.get().toString() == protoLogClassName ||
-                isLogClassImported && call.scope.isPresent &&
-                call.scope.get().toString() == protoLogSimpleClassName ||
-                !call.scope.isPresent && staticLogImports.contains(call.name.toString())
-    }
-
-    open fun process(code: CompilationUnit, callVisitor: ProtoLogCallVisitor?, fileName: String):
-            CompilationUnit {
-        CodeUtils.checkWildcardStaticImported(code, protoLogClassName, fileName)
-        CodeUtils.checkWildcardStaticImported(code, protoLogGroupClassName, fileName)
-
-        val isLogClassImported = CodeUtils.isClassImportedOrSamePackage(code, protoLogClassName)
-        val staticLogImports = CodeUtils.staticallyImportedMethods(code, protoLogClassName)
-        val isGroupClassImported = CodeUtils.isClassImportedOrSamePackage(code,
-                protoLogGroupClassName)
-        val staticGroupImports = CodeUtils.staticallyImportedMethods(code, protoLogGroupClassName)
-
-        code.findAll(MethodCallExpr::class.java)
-                .filter { call ->
-                    isProtoCall(call, isLogClassImported, staticLogImports)
-                }.forEach { call ->
-                    val context = ParsingContext(fileName, call)
-                    if (call.arguments.size < 2) {
-                        throw InvalidProtoLogCallException("Method signature does not match " +
-                                "any ProtoLog method: $call", context)
-                    }
-
-                    val messageString = CodeUtils.concatMultilineString(call.getArgument(1),
-                            context)
-                    val groupNameArg = call.getArgument(0)
-                    val groupName =
-                            getLogGroupName(groupNameArg, isGroupClassImported,
-                                    staticGroupImports, fileName)
-                    if (groupName !in groupMap) {
-                        throw InvalidProtoLogCallException("Unknown group argument " +
-                                "- not a ProtoLogGroup enum member: $call", context)
-                    }
-
-                    callVisitor?.processCall(call, messageString, getLevelForMethodName(
-                            call.name.toString(), call, context), groupMap.getValue(groupName))
-                }
-        return code
-    }
-
-    companion object {
-        fun getLevelForMethodName(name: String, node: Node, context: ParsingContext): LogLevel {
-            return when (name) {
-                "d" -> LogLevel.DEBUG
-                "v" -> LogLevel.VERBOSE
-                "i" -> LogLevel.INFO
-                "w" -> LogLevel.WARN
-                "e" -> LogLevel.ERROR
-                "wtf" -> LogLevel.WTF
-                else ->
-                    throw InvalidProtoLogCallException("Unknown log level $name in $node", context)
-            }
-        }
-    }
+    ): CompilationUnit
 }
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt
new file mode 100644
index 0000000..1087ae6
--- /dev/null
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt
@@ -0,0 +1,145 @@
+/*
+ * 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.protolog.tool
+
+import com.android.internal.protolog.common.LogLevel
+import com.github.javaparser.ast.CompilationUnit
+import com.github.javaparser.ast.expr.Expression
+import com.github.javaparser.ast.expr.FieldAccessExpr
+import com.github.javaparser.ast.expr.MethodCallExpr
+import com.github.javaparser.ast.expr.NameExpr
+
+/**
+ * Helper class for visiting all ProtoLog calls.
+ * For every valid call in the given {@code CompilationUnit} a {@code ProtoLogCallVisitor} callback
+ * is executed.
+ */
+class ProtoLogCallProcessorImpl(
+    private val protoLogClassName: String,
+    private val protoLogGroupClassName: String,
+    private val groupMap: Map<String, LogGroup>
+) : ProtoLogCallProcessor {
+    private val protoLogSimpleClassName = protoLogClassName.substringAfterLast('.')
+    private val protoLogGroupSimpleClassName = protoLogGroupClassName.substringAfterLast('.')
+
+    private fun getLogGroupName(
+        expr: Expression,
+        isClassImported: Boolean,
+        staticImports: Set<String>,
+        fileName: String
+    ): String {
+        val context = ParsingContext(fileName, expr)
+        return when (expr) {
+            is NameExpr -> when {
+                expr.nameAsString in staticImports -> expr.nameAsString
+                else ->
+                    throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr",
+                            context)
+            }
+            is FieldAccessExpr -> when {
+                expr.scope.toString() == protoLogGroupClassName || isClassImported &&
+                        expr.scope.toString() == protoLogGroupSimpleClassName -> expr.nameAsString
+                else ->
+                    throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr",
+                            context)
+            }
+            else -> throw InvalidProtoLogCallException("Invalid group argument " +
+                    "- must be ProtoLogGroup enum member reference: $expr", context)
+        }
+    }
+
+    private fun isProtoCall(
+        call: MethodCallExpr,
+        isLogClassImported: Boolean,
+        staticLogImports: Collection<String>
+    ): Boolean {
+        return call.scope.isPresent && call.scope.get().toString() == protoLogClassName ||
+                isLogClassImported && call.scope.isPresent &&
+                call.scope.get().toString() == protoLogSimpleClassName ||
+                !call.scope.isPresent && staticLogImports.contains(call.name.toString())
+    }
+
+    fun process(code: CompilationUnit, logCallVisitor: ProtoLogCallVisitor?, fileName: String):
+            CompilationUnit {
+        return process(code, logCallVisitor, null, fileName)
+    }
+
+    override fun process(
+        code: CompilationUnit,
+        logCallVisitor: ProtoLogCallVisitor?,
+        otherCallVisitor: MethodCallVisitor?,
+        fileName: String
+    ): CompilationUnit {
+        CodeUtils.checkWildcardStaticImported(code, protoLogClassName, fileName)
+        CodeUtils.checkWildcardStaticImported(code, protoLogGroupClassName, fileName)
+
+        val isLogClassImported = CodeUtils.isClassImportedOrSamePackage(code, protoLogClassName)
+        val staticLogImports = CodeUtils.staticallyImportedMethods(code, protoLogClassName)
+        val isGroupClassImported = CodeUtils.isClassImportedOrSamePackage(code,
+                protoLogGroupClassName)
+        val staticGroupImports = CodeUtils.staticallyImportedMethods(code, protoLogGroupClassName)
+
+        code.findAll(MethodCallExpr::class.java)
+                .filter { call ->
+                    isProtoCall(call, isLogClassImported, staticLogImports)
+                }.forEach { call ->
+                    val context = ParsingContext(fileName, call)
+
+                    val logMethods = LogLevel.entries.map { it.shortCode }
+                    if (logMethods.contains(call.name.id)) {
+                        // Process a log call
+                        if (call.arguments.size < 2) {
+                            throw InvalidProtoLogCallException("Method signature does not match " +
+                                    "any ProtoLog method: $call", context)
+                        }
+
+                        val messageString = CodeUtils.concatMultilineString(call.getArgument(1),
+                            context)
+                        val groupNameArg = call.getArgument(0)
+                        val groupName =
+                            getLogGroupName(groupNameArg, isGroupClassImported,
+                                staticGroupImports, fileName)
+                        if (groupName !in groupMap) {
+                            throw InvalidProtoLogCallException("Unknown group argument " +
+                                    "- not a ProtoLogGroup enum member: $call", context)
+                        }
+
+                        logCallVisitor?.processCall(call, messageString, getLevelForMethodName(
+                            call.name.toString(), call, context), groupMap.getValue(groupName))
+                    } else {
+                        // Process non-log message calls
+                        otherCallVisitor?.processCall(call)
+                    }
+                }
+        return code
+    }
+
+    private fun getLevelForMethodName(
+        name: String,
+        node: MethodCallExpr,
+        context: ParsingContext
+    ): LogLevel = when (name) {
+            "d" -> LogLevel.DEBUG
+            "v" -> LogLevel.VERBOSE
+            "i" -> LogLevel.INFO
+            "w" -> LogLevel.WARN
+            "e" -> LogLevel.ERROR
+            "wtf" -> LogLevel.WTF
+            else ->
+                throw InvalidProtoLogCallException("Unknown log level $name in $node", context)
+        }
+}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
index ce856cd..1381847 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
@@ -16,13 +16,22 @@
 
 package com.android.protolog.tool
 
+import com.android.internal.protolog.common.LogLevel
+import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.common.ProtoLogToolInjected
 import com.android.protolog.tool.CommandOptions.Companion.USAGE
 import com.github.javaparser.ParseProblemException
 import com.github.javaparser.ParserConfiguration
 import com.github.javaparser.StaticJavaParser
 import com.github.javaparser.ast.CompilationUnit
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
+import com.github.javaparser.ast.expr.MethodCallExpr
+import com.github.javaparser.ast.expr.NullLiteralExpr
+import com.github.javaparser.ast.expr.SimpleName
+import com.github.javaparser.ast.expr.StringLiteralExpr
 import java.io.File
 import java.io.FileInputStream
+import java.io.FileNotFoundException
 import java.io.FileOutputStream
 import java.io.OutputStream
 import java.time.LocalDateTime
@@ -30,9 +39,21 @@
 import java.util.concurrent.Executors
 import java.util.jar.JarOutputStream
 import java.util.zip.ZipEntry
+import kotlin.math.abs
+import kotlin.random.Random
 import kotlin.system.exitProcess
 
 object ProtoLogTool {
+    const val PROTOLOG_IMPL_SRC_PATH =
+        "frameworks/base/core/java/com/android/internal/protolog/ProtoLogImpl.java"
+
+    data class LogCall(
+        val messageString: String,
+        val logLevel: LogLevel,
+        val logGroup: LogGroup,
+        val position: String
+    )
+
     private fun showHelpAndExit() {
         println(USAGE)
         exitProcess(-1)
@@ -51,26 +72,40 @@
     }
 
     private fun processClasses(command: CommandOptions) {
+        val generationHash = abs(Random.nextInt())
+        // Need to generate a new impl class to inject static constants into the class.
+        val generatedProtoLogImplClass =
+            "com.android.internal.protolog.ProtoLogImpl_$generationHash"
+
         val groups = injector.readLogGroups(
                 command.protoLogGroupsJarArg,
                 command.protoLogGroupsClassNameArg)
         val out = injector.fileOutputStream(command.outputSourceJarArg)
         val outJar = JarOutputStream(out)
-        val processor = ProtoLogCallProcessor(command.protoLogClassNameArg,
-                command.protoLogGroupsClassNameArg, groups)
+        val processor = ProtoLogCallProcessorImpl(
+            command.protoLogClassNameArg,
+            command.protoLogGroupsClassNameArg,
+            groups)
+
+        val protologImplName = generatedProtoLogImplClass.split(".").last()
+        val protologImplPath = "gen/${generatedProtoLogImplClass.split(".")
+                .joinToString("/")}.java"
+        outJar.putNextEntry(zipEntry(protologImplPath))
+
+        outJar.write(generateProtoLogImpl(protologImplName, command.viewerConfigFilePathArg,
+            command.legacyViewerConfigFilePathArg, command.legacyOutputFilePath).toByteArray())
 
         val executor = newThreadPool()
 
         try {
             command.javaSourceArgs.map { path ->
                 executor.submitCallable {
-                    val transformer = SourceTransformer(command.protoLogImplClassNameArg,
-                            command.protoLogCacheClassNameArg, processor)
+                    val transformer = SourceTransformer(generatedProtoLogImplClass, processor)
                     val file = File(path)
                     val text = injector.readText(file)
                     val outSrc = try {
                         val code = tryParse(text, path)
-                        if (containsProtoLogText(text, command.protoLogClassNameArg)) {
+                        if (containsProtoLogText(text, ProtoLog::class.java.simpleName)) {
                             transformer.processClass(text, path, packagePath(file, code), code)
                         } else {
                             text
@@ -93,51 +128,77 @@
             executor.shutdown()
         }
 
-        val cacheSplit = command.protoLogCacheClassNameArg.split(".")
-        val cacheName = cacheSplit.last()
-        val cachePackage = cacheSplit.dropLast(1).joinToString(".")
-        val cachePath = "gen/${cacheSplit.joinToString("/")}.java"
-
-        outJar.putNextEntry(zipEntry(cachePath))
-        outJar.write(generateLogGroupCache(cachePackage, cacheName, groups,
-                command.protoLogImplClassNameArg, command.protoLogGroupsClassNameArg).toByteArray())
-
         outJar.close()
         out.close()
     }
 
-    fun generateLogGroupCache(
-        cachePackage: String,
-        cacheName: String,
-        groups: Map<String, LogGroup>,
-        protoLogImplClassName: String,
-        protoLogGroupsClassName: String
+    private fun generateProtoLogImpl(
+        protoLogImplGenName: String,
+        viewerConfigFilePath: String,
+        legacyViewerConfigFilePath: String?,
+        legacyOutputFilePath: String?,
     ): String {
-        val fields = groups.values.map {
-            "public static boolean ${it.name}_enabled = false;"
-        }.joinToString("\n")
+        val file = File(PROTOLOG_IMPL_SRC_PATH)
 
-        val updates = groups.values.map {
-            "${it.name}_enabled = " +
-                    "$protoLogImplClassName.isEnabled($protoLogGroupsClassName.${it.name});"
-        }.joinToString("\n")
+        val text = try {
+            injector.readText(file)
+        } catch (e: FileNotFoundException) {
+            throw RuntimeException("Expected to find '$PROTOLOG_IMPL_SRC_PATH' but file was not " +
+                    "included in source for the ProtoLog Tool to process.")
+        }
 
-        return """
-            package $cachePackage;
+        val code = tryParse(text, PROTOLOG_IMPL_SRC_PATH)
 
-            public class $cacheName {
-${fields.replaceIndent("                ")}
+        val classDeclarations = code.findAll(ClassOrInterfaceDeclaration::class.java)
+        require(classDeclarations.size == 1) { "Expected exactly one class declaration" }
+        val classDeclaration = classDeclarations[0]
 
-                static {
-                    $protoLogImplClassName.sCacheUpdater = $cacheName::update;
-                    update();
-                }
+        val classNameNode = classDeclaration.findFirst(SimpleName::class.java).get()
+        classNameNode.setId(protoLogImplGenName)
 
-                static void update() {
-${updates.replaceIndent("                    ")}
-                }
-            }
-        """.trimIndent()
+        injectConstants(classDeclaration,
+            viewerConfigFilePath, legacyViewerConfigFilePath, legacyOutputFilePath)
+
+        return code.toString()
+    }
+
+    private fun injectConstants(
+        classDeclaration: ClassOrInterfaceDeclaration,
+        viewerConfigFilePath: String,
+        legacyViewerConfigFilePath: String?,
+        legacyOutputFilePath: String?
+    ) {
+        classDeclaration.fields.forEach { field ->
+            field.getAnnotationByClass(ProtoLogToolInjected::class.java)
+                    .ifPresent { annotationExpr ->
+                        if (annotationExpr.isSingleMemberAnnotationExpr) {
+                            val valueName = annotationExpr.asSingleMemberAnnotationExpr()
+                                    .memberValue.asNameExpr().name.asString()
+                            when (valueName) {
+                                ProtoLogToolInjected.Value.VIEWER_CONFIG_PATH.name -> {
+                                    field.setFinal(true)
+                                    field.variables.first()
+                                            .setInitializer(StringLiteralExpr(viewerConfigFilePath))
+                                }
+                                ProtoLogToolInjected.Value.LEGACY_OUTPUT_FILE_PATH.name -> {
+                                    field.setFinal(true)
+                                    field.variables.first()
+                                            .setInitializer(legacyOutputFilePath?.let {
+                                                StringLiteralExpr(it)
+                                            } ?: NullLiteralExpr())
+                                }
+                                ProtoLogToolInjected.Value.LEGACY_VIEWER_CONFIG_PATH.name -> {
+                                    field.setFinal(true)
+                                    field.variables.first()
+                                            .setInitializer(legacyViewerConfigFilePath?.let {
+                                                StringLiteralExpr(it)
+                                            } ?: NullLiteralExpr())
+                                }
+                                else -> error("Unhandled ProtoLogToolInjected value: $valueName.")
+                            }
+                        }
+                    }
+        }
     }
 
     private fun tryParse(code: String, fileName: String): CompilationUnit {
@@ -145,24 +206,53 @@
             return StaticJavaParser.parse(code)
         } catch (ex: ParseProblemException) {
             val problem = ex.problems.first()
-            throw ParsingException("Java parsing erro" +
-                    "r: ${problem.verboseMessage}",
+            throw ParsingException("Java parsing error: ${problem.verboseMessage}",
                     ParsingContext(fileName, problem.location.orElse(null)
                             ?.begin?.range?.orElse(null)?.begin?.line
                             ?: 0))
         }
     }
 
+    class LogCallRegistry {
+        private val statements = mutableMapOf<LogCall, Long>()
+
+        fun addLogCalls(calls: List<LogCall>) {
+            calls.forEach { logCall ->
+                if (logCall.logGroup.enabled) {
+                    statements.putIfAbsent(logCall,
+                        CodeUtils.hash(logCall.position, logCall.messageString,
+                            logCall.logLevel, logCall.logGroup))
+                }
+            }
+        }
+
+        fun getStatements(): Map<LogCall, Long> {
+            return statements
+        }
+    }
+
+    interface ProtologViewerConfigBuilder {
+        fun build(statements: Map<LogCall, Long>): ByteArray
+    }
+
     private fun viewerConf(command: CommandOptions) {
         val groups = injector.readLogGroups(
                 command.protoLogGroupsJarArg,
                 command.protoLogGroupsClassNameArg)
-        val processor = ProtoLogCallProcessor(command.protoLogClassNameArg,
+        val processor = ProtoLogCallProcessorImpl(command.protoLogClassNameArg,
                 command.protoLogGroupsClassNameArg, groups)
-        val builder = ViewerConfigBuilder(processor)
+        val outputType = command.viewerConfigTypeArg
+
+        val configBuilder: ProtologViewerConfigBuilder = when (outputType.lowercase()) {
+            "json" -> ViewerConfigJsonBuilder()
+            "proto" -> ViewerConfigProtoBuilder()
+            else -> error("Invalid output type provide. Provided '$outputType'.")
+        }
 
         val executor = newThreadPool()
 
+        val logCallRegistry = LogCallRegistry()
+
         try {
             command.javaSourceArgs.map { path ->
                 executor.submitCallable {
@@ -171,7 +261,7 @@
                     if (containsProtoLogText(text, command.protoLogClassNameArg)) {
                         try {
                             val code = tryParse(text, path)
-                            builder.findLogCalls(code, path, packagePath(file, code))
+                            findLogCalls(code, path, packagePath(file, code), processor)
                         } catch (ex: ParsingException) {
                             // If we cannot parse this file, skip it (and log why). Compilation will
                             // fail in a subsequent build step.
@@ -183,15 +273,38 @@
                     }
                 }
             }.forEach { future ->
-                builder.addLogCalls(future.get() ?: return@forEach)
+                logCallRegistry.addLogCalls(future.get() ?: return@forEach)
             }
         } finally {
             executor.shutdown()
         }
 
-        val out = injector.fileOutputStream(command.viewerConfigJsonArg)
-        out.write(builder.build().toByteArray())
-        out.close()
+        val outFile = injector.fileOutputStream(command.viewerConfigFileNameArg)
+        outFile.write(configBuilder.build(logCallRegistry.getStatements()))
+        outFile.close()
+    }
+
+    private fun findLogCalls(
+        unit: CompilationUnit,
+        path: String,
+        packagePath: String,
+        processor: ProtoLogCallProcessorImpl
+    ): List<LogCall> {
+        val calls = mutableListOf<LogCall>()
+        val logCallVisitor = object : ProtoLogCallVisitor {
+            override fun processCall(
+                call: MethodCallExpr,
+                messageString: String,
+                level: LogLevel,
+                group: LogGroup
+            ) {
+                val logCall = LogCall(messageString, level, group, packagePath)
+                calls.add(logCall)
+            }
+        }
+        processor.process(unit, logCallVisitor, path)
+
+        return calls
     }
 
     private fun packagePath(file: File, code: CompilationUnit): String {
@@ -204,7 +317,7 @@
     private fun read(command: CommandOptions) {
         LogParser(ViewerConfigParser())
                 .parse(FileInputStream(command.logProtofileArg),
-                        FileInputStream(command.viewerConfigJsonArg), System.out)
+                        FileInputStream(command.viewerConfigFileNameArg), System.out)
     }
 
     @JvmStatic
diff --git a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
index b50f357..2b71641 100644
--- a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
@@ -22,11 +22,11 @@
 import com.github.javaparser.ast.CompilationUnit
 import com.github.javaparser.ast.NodeList
 import com.github.javaparser.ast.body.VariableDeclarator
-import com.github.javaparser.ast.expr.BooleanLiteralExpr
 import com.github.javaparser.ast.expr.CastExpr
 import com.github.javaparser.ast.expr.Expression
 import com.github.javaparser.ast.expr.FieldAccessExpr
 import com.github.javaparser.ast.expr.IntegerLiteralExpr
+import com.github.javaparser.ast.expr.LongLiteralExpr
 import com.github.javaparser.ast.expr.MethodCallExpr
 import com.github.javaparser.ast.expr.NameExpr
 import com.github.javaparser.ast.expr.NullLiteralExpr
@@ -35,7 +35,6 @@
 import com.github.javaparser.ast.expr.VariableDeclarationExpr
 import com.github.javaparser.ast.stmt.BlockStmt
 import com.github.javaparser.ast.stmt.ExpressionStmt
-import com.github.javaparser.ast.stmt.IfStmt
 import com.github.javaparser.ast.type.ArrayType
 import com.github.javaparser.ast.type.ClassOrInterfaceType
 import com.github.javaparser.ast.type.PrimitiveType
@@ -45,15 +44,59 @@
 
 class SourceTransformer(
     protoLogImplClassName: String,
-    protoLogCacheClassName: String,
     private val protoLogCallProcessor: ProtoLogCallProcessor
-) : ProtoLogCallVisitor {
-    override fun processCall(
-        call: MethodCallExpr,
-        messageString: String,
-        level: LogLevel,
-        group: LogGroup
-    ) {
+) {
+    private val inlinePrinter: PrettyPrinter
+    private val objectType = StaticJavaParser.parseClassOrInterfaceType("Object")
+
+    init {
+        val config = PrettyPrinterConfiguration()
+        config.endOfLineCharacter = " "
+        config.indentSize = 0
+        config.tabWidth = 1
+        inlinePrinter = PrettyPrinter(config)
+    }
+
+    fun processClass(
+        code: String,
+        path: String,
+        packagePath: String,
+        compilationUnit: CompilationUnit =
+            StaticJavaParser.parse(code)
+    ): String {
+        this.path = path
+        this.packagePath = packagePath
+        processedCode = code.split('\n').toMutableList()
+        offsets = IntArray(processedCode.size)
+        protoLogCallProcessor.process(compilationUnit, protoLogCallVisitor, otherCallVisitor, path)
+        return processedCode.joinToString("\n")
+    }
+
+    private val protoLogImplClassNode =
+            StaticJavaParser.parseExpression<FieldAccessExpr>(protoLogImplClassName)
+    private var processedCode: MutableList<String> = mutableListOf()
+    private var offsets: IntArray = IntArray(0)
+    /** The path of the file being processed, relative to $ANDROID_BUILD_TOP */
+    private var path: String = ""
+    /** The path of the file being processed, relative to the root package */
+    private var packagePath: String = ""
+
+    private val protoLogCallVisitor = object : ProtoLogCallVisitor {
+        override fun processCall(
+            call: MethodCallExpr,
+            messageString: String,
+            level: LogLevel,
+            group: LogGroup
+        ) {
+            validateCall(call)
+            val processedCallStatement =
+                createProcessedCallStatement(call, group, level, messageString)
+            val parentStmt = call.parentNode.get() as ExpressionStmt
+            injectProcessedCallStatementInCode(processedCallStatement, parentStmt)
+        }
+    }
+
+    private fun validateCall(call: MethodCallExpr) {
         // Input format: ProtoLog.e(GROUP, "msg %d", arg)
         if (!call.parentNode.isPresent) {
             // Should never happen
@@ -71,89 +114,79 @@
             throw RuntimeException("Unable to process log call $call " +
                     "- no grandparent node in AST")
         }
-        val ifStmt: IfStmt
-        if (group.enabled) {
-            val hash = CodeUtils.hash(packagePath, messageString, level, group)
-            val newCall = call.clone()
-            if (!group.textEnabled) {
-                // Remove message string if text logging is not enabled by default.
-                // Out: ProtoLog.e(GROUP, null, arg)
-                newCall.arguments[1].replace(NameExpr("null"))
-            }
-            // Insert message string hash as a second argument.
-            // Out: ProtoLog.e(GROUP, 1234, null, arg)
-            newCall.arguments.add(1, IntegerLiteralExpr(hash))
-            val argTypes = LogDataType.parseFormatString(messageString)
-            val typeMask = LogDataType.logDataTypesToBitMask(argTypes)
-            // Insert bitmap representing which Number parameters are to be considered as
-            // floating point numbers.
-            // Out: ProtoLog.e(GROUP, 1234, 0, null, arg)
-            newCall.arguments.add(2, IntegerLiteralExpr(typeMask))
-            // Replace call to a stub method with an actual implementation.
-            // Out: ProtoLogImpl.e(GROUP, 1234, null, arg)
-            newCall.setScope(protoLogImplClassNode)
-            // Create a call to ProtoLog$Cache.GROUP_enabled
-            // Out: com.android.server.protolog.ProtoLog$Cache.GROUP_enabled
-            val isLogEnabled = FieldAccessExpr(protoLogCacheClassNode, "${group.name}_enabled")
-            if (argTypes.size != call.arguments.size - 2) {
-                throw InvalidProtoLogCallException(
-                        "Number of arguments (${argTypes.size} does not mach format" +
-                                " string in: $call", ParsingContext(path, call))
-            }
-            val blockStmt = BlockStmt()
-            if (argTypes.isNotEmpty()) {
-                // Assign every argument to a variable to check its type in compile time
-                // (this is assignment is optimized-out by dex tool, there is no runtime impact)/
-                // Out: long protoLogParam0 = arg
-                argTypes.forEachIndexed { idx, type ->
-                    val varName = "protoLogParam$idx"
-                    val declaration = VariableDeclarator(getASTTypeForDataType(type), varName,
-                            getConversionForType(type)(newCall.arguments[idx + 4].clone()))
-                    blockStmt.addStatement(ExpressionStmt(VariableDeclarationExpr(declaration)))
-                    newCall.setArgument(idx + 4, NameExpr(SimpleName(varName)))
-                }
-            } else {
-                // Assign (Object[])null as the vararg parameter to prevent allocating an empty
-                // object array.
-                val nullArray = CastExpr(ArrayType(objectType), NullLiteralExpr())
-                newCall.addArgument(nullArray)
-            }
-            blockStmt.addStatement(ExpressionStmt(newCall))
-            // Create an IF-statement with the previously created condition.
-            // Out: if (ProtoLogImpl.isEnabled(GROUP)) {
-            //          long protoLogParam0 = arg;
-            //          ProtoLogImpl.e(GROUP, 1234, 0, null, protoLogParam0);
-            //      }
-            ifStmt = IfStmt(isLogEnabled, blockStmt, null)
-        } else {
-            // Surround with if (false).
-            val newCall = parentStmt.clone()
-            ifStmt = IfStmt(BooleanLiteralExpr(false), BlockStmt(NodeList(newCall)), null)
-            newCall.setBlockComment(" ${group.name} is disabled ")
+    }
+
+    private fun createProcessedCallStatement(
+        call: MethodCallExpr,
+        group: LogGroup,
+        level: LogLevel,
+        messageString: String
+    ): BlockStmt {
+        val hash = CodeUtils.hash(packagePath, messageString, level, group)
+        val newCall = call.clone()
+        if (!group.textEnabled) {
+            // Remove message string if text logging is not enabled by default.
+            // Out: ProtoLog.e(GROUP, null, arg)
+            newCall.arguments[1].replace(NameExpr("null"))
         }
+        // Insert message string hash as a second argument.
+        // Out: ProtoLog.e(GROUP, 1234, null, arg)
+        newCall.arguments.add(1, LongLiteralExpr("" + hash + "L"))
+        val argTypes = LogDataType.parseFormatString(messageString)
+        val typeMask = LogDataType.logDataTypesToBitMask(argTypes)
+        // Insert bitmap representing which Number parameters are to be considered as
+        // floating point numbers.
+        // Out: ProtoLog.e(GROUP, 1234, 0, null, arg)
+        newCall.arguments.add(2, IntegerLiteralExpr(typeMask))
+        // Replace call to a stub method with an actual implementation.
+        // Out: ProtoLogImpl.e(GROUP, 1234, null, arg)
+        newCall.setScope(protoLogImplClassNode)
+        if (argTypes.size != call.arguments.size - 2) {
+            throw InvalidProtoLogCallException(
+                "Number of arguments (${argTypes.size} does not match format" +
+                        " string in: $call", ParsingContext(path, call))
+        }
+        val blockStmt = BlockStmt()
+        if (argTypes.isNotEmpty()) {
+            // Assign every argument to a variable to check its type in compile time
+            // (this is assignment is optimized-out by dex tool, there is no runtime impact)/
+            // Out: long protoLogParam0 = arg
+            argTypes.forEachIndexed { idx, type ->
+                val varName = "protoLogParam$idx"
+                val declaration = VariableDeclarator(getASTTypeForDataType(type), varName,
+                    getConversionForType(type)(newCall.arguments[idx + 4].clone()))
+                blockStmt.addStatement(ExpressionStmt(VariableDeclarationExpr(declaration)))
+                newCall.setArgument(idx + 4, NameExpr(SimpleName(varName)))
+            }
+        } else {
+            // Assign (Object[])null as the vararg parameter to prevent allocating an empty
+            // object array.
+            val nullArray = CastExpr(ArrayType(objectType), NullLiteralExpr())
+            newCall.addArgument(nullArray)
+        }
+        blockStmt.addStatement(ExpressionStmt(newCall))
+
+        return blockStmt
+    }
+
+    private fun injectProcessedCallStatementInCode(
+        processedCallStatement: BlockStmt,
+        parentStmt: ExpressionStmt
+    ) {
         // Inline the new statement.
-        val printedIfStmt = inlinePrinter.print(ifStmt)
+        val printedBlockStmt = inlinePrinter.print(processedCallStatement)
         // Append blank lines to preserve line numbering in file (to allow debugging)
         val parentRange = parentStmt.range.get()
         val newLines = parentRange.end.line - parentRange.begin.line
-        val newStmt = printedIfStmt.substringBeforeLast('}') + ("\n".repeat(newLines)) + '}'
+        val newStmt = printedBlockStmt.substringBeforeLast('}') + ("\n".repeat(newLines)) + '}'
         // pre-workaround code, see explanation below
-        /*
-        val inlinedIfStmt = StaticJavaParser.parseStatement(newStmt)
-        LexicalPreservingPrinter.setup(inlinedIfStmt)
-        // Replace the original call.
-        if (!parentStmt.replace(inlinedIfStmt)) {
-            // Should never happen
-            throw RuntimeException("Unable to process log call $call " +
-                    "- unable to replace the call.")
-        }
-        */
+
         /** Workaround for a bug in JavaParser (AST tree invalid after replacing a node when using
          * LexicalPreservingPrinter (https://github.com/javaparser/javaparser/issues/2290).
          * Replace the code below with the one commended-out above one the issue is resolved. */
         if (!parentStmt.range.isPresent) {
             // Should never happen
-            throw RuntimeException("Unable to process log call $call " +
+            throw RuntimeException("Unable to process log call in $parentStmt " +
                     "- unable to replace the call.")
         }
         val range = parentStmt.range.get()
@@ -161,29 +194,38 @@
         val oldLines = processedCode.subList(begin, range.end.line)
         val oldCode = oldLines.joinToString("\n")
         val newCode = oldCode.replaceRange(
-                offsets[begin] + range.begin.column - 1,
-                oldCode.length - oldLines.lastOrNull()!!.length +
-                        range.end.column + offsets[range.end.line - 1], newStmt)
+            offsets[begin] + range.begin.column - 1,
+            oldCode.length - oldLines.lastOrNull()!!.length +
+                    range.end.column + offsets[range.end.line - 1], newStmt)
         newCode.split("\n").forEachIndexed { idx, line ->
             offsets[begin + idx] += line.length - processedCode[begin + idx].length
             processedCode[begin + idx] = line
         }
     }
 
-    private val inlinePrinter: PrettyPrinter
-    private val objectType = StaticJavaParser.parseClassOrInterfaceType("Object")
+    private val otherCallVisitor = object : MethodCallVisitor {
+        override fun processCall(call: MethodCallExpr) {
+            val newCall = call.clone()
+            newCall.setScope(protoLogImplClassNode)
 
-    init {
-        val config = PrettyPrinterConfiguration()
-        config.endOfLineCharacter = " "
-        config.indentSize = 0
-        config.tabWidth = 1
-        inlinePrinter = PrettyPrinter(config)
+            val range = call.range.get()
+            val begin = range.begin.line - 1
+            val oldLines = processedCode.subList(begin, range.end.line)
+            val oldCode = oldLines.joinToString("\n")
+            val newCode = oldCode.replaceRange(
+                offsets[begin] + range.begin.column - 1,
+                oldCode.length - oldLines.lastOrNull()!!.length +
+                        range.end.column + offsets[range.end.line - 1], newCall.toString())
+            newCode.split("\n").forEachIndexed { idx, line ->
+                offsets[begin + idx] += line.length - processedCode[begin + idx].length
+                processedCode[begin + idx] = line
+            }
+        }
     }
 
     companion object {
         private val stringType: ClassOrInterfaceType =
-                StaticJavaParser.parseClassOrInterfaceType("String")
+            StaticJavaParser.parseClassOrInterfaceType("String")
 
         fun getASTTypeForDataType(type: Int): Type {
             return when (type) {
@@ -202,36 +244,10 @@
             return when (type) {
                 LogDataType.STRING -> { expr ->
                     MethodCallExpr(TypeExpr(StaticJavaParser.parseClassOrInterfaceType("String")),
-                            SimpleName("valueOf"), NodeList(expr))
+                        SimpleName("valueOf"), NodeList(expr))
                 }
                 else -> { expr -> expr }
             }
         }
     }
-
-    private val protoLogImplClassNode =
-            StaticJavaParser.parseExpression<FieldAccessExpr>(protoLogImplClassName)
-    private val protoLogCacheClassNode =
-            StaticJavaParser.parseExpression<FieldAccessExpr>(protoLogCacheClassName)
-    private var processedCode: MutableList<String> = mutableListOf()
-    private var offsets: IntArray = IntArray(0)
-    /** The path of the file being processed, relative to $ANDROID_BUILD_TOP */
-    private var path: String = ""
-    /** The path of the file being processed, relative to the root package */
-    private var packagePath: String = ""
-
-    fun processClass(
-        code: String,
-        path: String,
-        packagePath: String,
-        compilationUnit: CompilationUnit =
-               StaticJavaParser.parse(code)
-    ): String {
-        this.path = path
-        this.packagePath = packagePath
-        processedCode = code.split('\n').toMutableList()
-        offsets = IntArray(processedCode.size)
-        protoLogCallProcessor.process(compilationUnit, this, path)
-        return processedCode.joinToString("\n")
-    }
 }
diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt
deleted file mode 100644
index 0d5d022..0000000
--- a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt
+++ /dev/null
@@ -1,125 +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.protolog.tool
-
-import com.android.internal.protolog.common.LogLevel
-import com.android.json.stream.JsonWriter
-import com.github.javaparser.ast.CompilationUnit
-import com.android.protolog.tool.Constants.VERSION
-import com.github.javaparser.ast.expr.MethodCallExpr
-import java.io.StringWriter
-
-class ViewerConfigBuilder(
-    private val processor: ProtoLogCallProcessor
-) {
-    private fun addLogCall(logCall: LogCall, context: ParsingContext) {
-        val group = logCall.logGroup
-        val messageString = logCall.messageString
-        if (group.enabled) {
-            val key = logCall.key()
-            if (statements.containsKey(key)) {
-                if (statements[key] != logCall) {
-                    throw HashCollisionException(
-                            "Please modify the log message \"$messageString\" " +
-                                    "or \"${statements[key]}\" - their hashes are equal.", context)
-                }
-            } else {
-                groups.add(group)
-                statements[key] = logCall
-            }
-        }
-    }
-
-    private val statements: MutableMap<Int, LogCall> = mutableMapOf()
-    private val groups: MutableSet<LogGroup> = mutableSetOf()
-
-    fun findLogCalls(
-        unit: CompilationUnit,
-        path: String,
-        packagePath: String
-    ): List<Pair<LogCall, ParsingContext>> {
-        val calls = mutableListOf<Pair<LogCall, ParsingContext>>()
-        val visitor = object : ProtoLogCallVisitor {
-            override fun processCall(
-                call: MethodCallExpr,
-                messageString: String,
-                level: LogLevel,
-                group: LogGroup
-            ) {
-                val logCall = LogCall(messageString, level, group, packagePath)
-                val context = ParsingContext(path, call)
-                calls.add(logCall to context)
-            }
-        }
-        processor.process(unit, visitor, path)
-
-        return calls
-    }
-
-    fun addLogCalls(calls: List<Pair<LogCall, ParsingContext>>) {
-        calls.forEach { (logCall, context) ->
-            addLogCall(logCall, context)
-        }
-    }
-
-    fun build(): String {
-        val stringWriter = StringWriter()
-        val writer = JsonWriter(stringWriter)
-        writer.setIndent("  ")
-        writer.beginObject()
-        writer.name("version")
-        writer.value(VERSION)
-        writer.name("messages")
-        writer.beginObject()
-        statements.toSortedMap().forEach { (key, value) ->
-            writer.name(key.toString())
-            writer.beginObject()
-            writer.name("message")
-            writer.value(value.messageString)
-            writer.name("level")
-            writer.value(value.logLevel.name)
-            writer.name("group")
-            writer.value(value.logGroup.name)
-            writer.name("at")
-            writer.value(value.position)
-            writer.endObject()
-        }
-        writer.endObject()
-        writer.name("groups")
-        writer.beginObject()
-        groups.toSortedSet(Comparator { o1, o2 -> o1.name.compareTo(o2.name) }).forEach { group ->
-            writer.name(group.name)
-            writer.beginObject()
-            writer.name("tag")
-            writer.value(group.tag)
-            writer.endObject()
-        }
-        writer.endObject()
-        writer.endObject()
-        stringWriter.buffer.append('\n')
-        return stringWriter.toString()
-    }
-
-    data class LogCall(
-        val messageString: String,
-        val logLevel: LogLevel,
-        val logGroup: LogGroup,
-        val position: String
-    ) {
-        fun key() = CodeUtils.hash(position, messageString, logLevel, logGroup)
-    }
-}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigJsonBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigJsonBuilder.kt
new file mode 100644
index 0000000..7714db2
--- /dev/null
+++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigJsonBuilder.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.protolog.tool
+
+import com.android.json.stream.JsonWriter
+import com.android.protolog.tool.Constants.VERSION
+import java.io.StringWriter
+
+class ViewerConfigJsonBuilder : ProtoLogTool.ProtologViewerConfigBuilder {
+    override fun build(statements: Map<ProtoLogTool.LogCall, Long>): ByteArray {
+        val groups = statements.map { it.key.logGroup }.toSet()
+        val stringWriter = StringWriter()
+        val writer = JsonWriter(stringWriter)
+        writer.setIndent("  ")
+        writer.beginObject()
+        writer.name("version")
+        writer.value(VERSION)
+        writer.name("messages")
+        writer.beginObject()
+        statements.forEach { (log, key) ->
+            writer.name(key.toString())
+            writer.beginObject()
+            writer.name("message")
+            writer.value(log.messageString)
+            writer.name("level")
+            writer.value(log.logLevel.name)
+            writer.name("group")
+            writer.value(log.logGroup.name)
+            writer.name("at")
+            writer.value(log.position)
+            writer.endObject()
+        }
+        writer.endObject()
+        writer.name("groups")
+        writer.beginObject()
+        groups.toSortedSet { o1, o2 -> o1.name.compareTo(o2.name) }.forEach { group ->
+            writer.name(group.name)
+            writer.beginObject()
+            writer.name("tag")
+            writer.value(group.tag)
+            writer.endObject()
+        }
+        writer.endObject()
+        writer.endObject()
+        stringWriter.buffer.append('\n')
+        return stringWriter.toString().toByteArray()
+    }
+}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigParser.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigParser.kt
index 7278db0..58be3a3 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigParser.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigParser.kt
@@ -63,12 +63,12 @@
         return GroupEntry(tag)
     }
 
-    fun parseMessages(jsonReader: JsonReader): Map<Int, MessageEntry> {
-        val config: MutableMap<Int, MessageEntry> = mutableMapOf()
+    fun parseMessages(jsonReader: JsonReader): Map<Long, MessageEntry> {
+        val config: MutableMap<Long, MessageEntry> = mutableMapOf()
         jsonReader.beginObject()
         while (jsonReader.hasNext()) {
             val key = jsonReader.nextName()
-            val hash = key.toIntOrNull()
+            val hash = key.toLongOrNull()
                     ?: throw InvalidViewerConfigException("Invalid key in messages viewer config")
             config[hash] = parseMessage(jsonReader)
         }
@@ -89,8 +89,8 @@
 
     data class ConfigEntry(val messageString: String, val level: String, val tag: String)
 
-    open fun parseConfig(jsonReader: JsonReader): Map<Int, ConfigEntry> {
-        var messages: Map<Int, MessageEntry>? = null
+    open fun parseConfig(jsonReader: JsonReader): Map<Long, ConfigEntry> {
+        var messages: Map<Long, MessageEntry>? = null
         var groups: Map<String, GroupEntry>? = null
         var version: String? = null
 
diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt
new file mode 100644
index 0000000..cf0876a
--- /dev/null
+++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.protolog.tool
+
+import perfetto.protos.PerfettoTrace.ProtoLogLevel
+import perfetto.protos.PerfettoTrace.ProtoLogViewerConfig
+
+/**
+ * A builder class to construct the viewer configuration (i.e. mappings of protolog hashes to log
+ * message information used to decode the protolog messages) encoded as a proto message.
+ */
+class ViewerConfigProtoBuilder : ProtoLogTool.ProtologViewerConfigBuilder {
+    /**
+     * @return a byte array of a ProtoLogViewerConfig proto message encoding all the viewer
+     * configurations mapping protolog hashes to message information and log group information.
+     */
+    override fun build(statements: Map<ProtoLogTool.LogCall, Long>): ByteArray {
+        val configBuilder = ProtoLogViewerConfig.newBuilder()
+
+        val groups = statements.map { it.key.logGroup }.toSet()
+        val groupIds = mutableMapOf<LogGroup, Int>()
+        groups.forEach {
+            groupIds.putIfAbsent(it, groupIds.size + 1)
+        }
+
+        groupIds.forEach { (group, id) ->
+            configBuilder.addGroups(ProtoLogViewerConfig.Group.newBuilder()
+                    .setId(id)
+                    .setName(group.name)
+                    .setTag(group.tag)
+                    .build())
+        }
+
+        statements.forEach { (log, key) ->
+            val groupId = groupIds[log.logGroup] ?: error("missing group id")
+
+            configBuilder.addMessages(
+                ProtoLogViewerConfig.MessageData.newBuilder()
+                        .setMessageId(key)
+                        .setMessage(log.messageString)
+                        .setLevel(
+                            ProtoLogLevel.forNumber(log.logLevel.ordinal + 1))
+                        .setGroupId(groupId)
+            )
+        }
+
+        return configBuilder.build().toByteArray()
+    }
+}
diff --git a/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt b/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt
index b08d859..0cd02a5c 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt
@@ -28,31 +28,31 @@
 class CodeUtilsTest {
     @Test
     fun hash() {
-        assertEquals(-1259556708, CodeUtils.hash("Test.java:50", "test",
+        assertEquals(3883826472308915399, CodeUtils.hash("Test.java:50", "test",
                 LogLevel.DEBUG, LogGroup("test", true, true, "TAG")))
     }
 
     @Test
     fun hash_changeLocation() {
-        assertEquals(15793504, CodeUtils.hash("Test.java:10", "test2",
+        assertEquals(4125273133972468649, CodeUtils.hash("Test.java:10", "test2",
                 LogLevel.DEBUG, LogGroup("test", true, true, "TAG")))
     }
 
     @Test
     fun hash_changeLevel() {
-        assertEquals(-731772463, CodeUtils.hash("Test.java:50", "test",
+        assertEquals(2618535069521361990, CodeUtils.hash("Test.java:50", "test",
                 LogLevel.ERROR, LogGroup("test", true, true, "TAG")))
     }
 
     @Test
     fun hash_changeMessage() {
-        assertEquals(-2026343204, CodeUtils.hash("Test.java:50", "test2",
+        assertEquals(8907822592109789043, CodeUtils.hash("Test.java:50", "test2",
                 LogLevel.DEBUG, LogGroup("test", true, true, "TAG")))
     }
 
     @Test
     fun hash_changeGroup() {
-        assertEquals(1607870166, CodeUtils.hash("Test.java:50", "test2",
+        assertEquals(-1299517016176640015, CodeUtils.hash("Test.java:50", "test2",
                 LogLevel.DEBUG, LogGroup("test2", true, true, "TAG")))
     }
 
diff --git a/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt b/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt
index 3cfbb43..5ef2833 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt
@@ -16,7 +16,9 @@
 
 package com.android.protolog.tool
 
+import com.google.common.truth.Truth.assertThat
 import org.junit.Assert.assertEquals
+import org.junit.Assert.assertThrows
 import org.junit.Test
 
 class CommandOptionsTest {
@@ -35,6 +37,10 @@
         private const val TEST_PROTOLOGGROUP_JAR = "out/soong/.intermediates/frameworks/base/" +
                 "services/core/services.core.wm.protologgroups/android_common/javac/" +
                 "services.core.wm.protologgroups.jar"
+        private const val TEST_VIEWER_CONFIG_FILE_PATH = "/some/viewer/config/file/path.pb"
+        private const val TEST_LEGACY_VIEWER_CONFIG_FILE_PATH =
+            "/some/viewer/config/file/path.json.gz"
+        private const val TEST_LEGACY_OUTPUT_FILE_PATH = "/some/output/file/path.winscope"
         private const val TEST_SRC_JAR = "out/soong/.temp/sbox175955373/" +
                 "services.core.wm.protolog.srcjar"
         private const val TEST_VIEWER_JSON = "out/soong/.temp/sbox175955373/" +
@@ -42,186 +48,263 @@
         private const val TEST_LOG = "./test_log.pb"
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun noCommand() {
-        CommandOptions(arrayOf())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(arrayOf())
+        }
+        assertThat(exception).hasMessageThat().contains("No command specified")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun invalidCommand() {
         val testLine = "invalid"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("Unknown command")
     }
 
     @Test
     fun transformClasses() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
                 "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
         val cmd = CommandOptions(testLine.split(' ').toTypedArray())
         assertEquals(CommandOptions.TRANSFORM_CALLS_CMD, cmd.command)
         assertEquals(TEST_PROTOLOG_CLASS, cmd.protoLogClassNameArg)
-        assertEquals(TEST_PROTOLOGIMPL_CLASS, cmd.protoLogImplClassNameArg)
         assertEquals(TEST_PROTOLOGGROUP_CLASS, cmd.protoLogGroupsClassNameArg)
         assertEquals(TEST_PROTOLOGGROUP_JAR, cmd.protoLogGroupsJarArg)
+        assertEquals(TEST_VIEWER_CONFIG_FILE_PATH, cmd.viewerConfigFilePathArg)
+        assertEquals(TEST_LEGACY_VIEWER_CONFIG_FILE_PATH, cmd.legacyViewerConfigFilePathArg)
+        assertEquals(TEST_LEGACY_OUTPUT_FILE_PATH, cmd.legacyOutputFilePath)
         assertEquals(TEST_SRC_JAR, cmd.outputSourceJarArg)
         assertEquals(TEST_JAVA_SRC, cmd.javaSourceArgs)
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
+    fun transformClasses_noViewerConfigFile() {
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
+                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
+                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
+                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("--viewer-config-file-path")
+    }
+
+    @Test
+    fun transformClasses_noLegacyViewerConfigFile() {
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
+                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
+                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
+                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
+        val cmd = CommandOptions(testLine.split(' ').toTypedArray())
+        assertEquals(CommandOptions.TRANSFORM_CALLS_CMD, cmd.command)
+        assertEquals(TEST_PROTOLOG_CLASS, cmd.protoLogClassNameArg)
+        assertEquals(TEST_PROTOLOGGROUP_CLASS, cmd.protoLogGroupsClassNameArg)
+        assertEquals(TEST_PROTOLOGGROUP_JAR, cmd.protoLogGroupsJarArg)
+        assertEquals(TEST_VIEWER_CONFIG_FILE_PATH, cmd.viewerConfigFilePathArg)
+        assertEquals(null, cmd.legacyViewerConfigFilePathArg)
+        assertEquals(TEST_LEGACY_OUTPUT_FILE_PATH, cmd.legacyOutputFilePath)
+        assertEquals(TEST_SRC_JAR, cmd.outputSourceJarArg)
+        assertEquals(TEST_JAVA_SRC, cmd.javaSourceArgs)
+    }
+
+    @Test
+    fun transformClasses_noLegacyOutputFile() {
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
+                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
+                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
+        val cmd = CommandOptions(testLine.split(' ').toTypedArray())
+        assertEquals(CommandOptions.TRANSFORM_CALLS_CMD, cmd.command)
+        assertEquals(TEST_PROTOLOG_CLASS, cmd.protoLogClassNameArg)
+        assertEquals(TEST_PROTOLOGGROUP_CLASS, cmd.protoLogGroupsClassNameArg)
+        assertEquals(TEST_PROTOLOGGROUP_JAR, cmd.protoLogGroupsJarArg)
+        assertEquals(TEST_VIEWER_CONFIG_FILE_PATH, cmd.viewerConfigFilePathArg)
+        assertEquals(TEST_LEGACY_VIEWER_CONFIG_FILE_PATH, cmd.legacyViewerConfigFilePathArg)
+        assertEquals(null, cmd.legacyOutputFilePath)
+        assertEquals(TEST_SRC_JAR, cmd.outputSourceJarArg)
+        assertEquals(TEST_JAVA_SRC, cmd.javaSourceArgs)
+    }
+
+    @Test
     fun transformClasses_noProtoLogClass() {
         val testLine = "transform-protolog-calls " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
                 "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("--protolog-class")
     }
 
-    @Test(expected = InvalidCommandException::class)
-    fun transformClasses_noProtoLogImplClass() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
-                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
-                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
-    }
-
-    @Test(expected = InvalidCommandException::class)
-    fun transformClasses_noProtoLogCacheClass() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
-                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
-    }
-
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_noProtoLogGroupClass() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
                 "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("--loggroups-class")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_noProtoLogGroupJar() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
                 "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("--loggroups-jar")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_noOutJar() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                TEST_JAVA_SRC.joinToString(" ")
-        CommandOptions(testLine.split(' ').toTypedArray())
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
+                "${TEST_JAVA_SRC.joinToString(" ")}"
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("--output-srcjar")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_noJavaInput() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
                 "--output-srcjar $TEST_SRC_JAR"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("No java source input files")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_invalidProtoLogClass() {
-        val testLine = "transform-protolog-calls --protolog-class invalid " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class invalid " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
                 "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("class name invalid")
     }
 
-    @Test(expected = InvalidCommandException::class)
-    fun transformClasses_invalidProtoLogImplClass() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class invalid " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
-                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
-                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
-    }
-
-    @Test(expected = InvalidCommandException::class)
-    fun transformClasses_invalidProtoLogCacheClass() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class invalid " +
-                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
-                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
-    }
-
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_invalidProtoLogGroupClass() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class invalid " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
                 "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("class name invalid")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_invalidProtoLogGroupJar() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar invalid.txt " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
                 "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat()
+                .contains("Jar file required, got invalid.txt instead")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_invalidOutJar() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--output-srcjar invalid.db ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
+                "--output-srcjar invalid.pb ${TEST_JAVA_SRC.joinToString(" ")}"
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat()
+                .contains("Source jar file required, got invalid.pb instead")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_invalidJavaInput() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
-                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
-                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--output-srcjar $TEST_SRC_JAR invalid.py"
-        CommandOptions(testLine.split(' ').toTypedArray())
+            val testLine = "transform-protolog-calls " +
+                    "--protolog-class $TEST_PROTOLOG_CLASS " +
+                    "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
+                    "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                    "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                    "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                    "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
+                    "--output-srcjar $TEST_SRC_JAR invalid.py"
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat()
+                .contains("Not a java or kotlin source file invalid.py")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_unknownParam() {
         val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
                 "--unknown test --protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
@@ -229,59 +312,88 @@
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
                 "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
-    }
-
-    @Test(expected = InvalidCommandException::class)
-    fun transformClasses_noValue() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
-                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
-                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("--unknown")
     }
 
     @Test
-    fun generateConfig() {
-        val testLine = "generate-viewer-config --protolog-class $TEST_PROTOLOG_CLASS " +
+    fun transformClasses_noValue() {
+        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
+                "--loggroups-class " +
+                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("No value for --loggroups-class")
+    }
+
+    @Test
+    fun generateConfig_json() {
+        val testLine = "generate-viewer-config " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--viewer-conf $TEST_VIEWER_JSON ${TEST_JAVA_SRC.joinToString(" ")}"
+                "--viewer-config-type json " +
+                "--viewer-config $TEST_VIEWER_JSON ${TEST_JAVA_SRC.joinToString(" ")}"
         val cmd = CommandOptions(testLine.split(' ').toTypedArray())
         assertEquals(CommandOptions.GENERATE_CONFIG_CMD, cmd.command)
         assertEquals(TEST_PROTOLOG_CLASS, cmd.protoLogClassNameArg)
         assertEquals(TEST_PROTOLOGGROUP_CLASS, cmd.protoLogGroupsClassNameArg)
         assertEquals(TEST_PROTOLOGGROUP_JAR, cmd.protoLogGroupsJarArg)
-        assertEquals(TEST_VIEWER_JSON, cmd.viewerConfigJsonArg)
+        assertEquals(TEST_VIEWER_JSON, cmd.viewerConfigFileNameArg)
         assertEquals(TEST_JAVA_SRC, cmd.javaSourceArgs)
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
+    fun generateConfig_proto() {
+        val testLine = "generate-viewer-config " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
+                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
+                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-type proto " +
+                "--viewer-config $TEST_VIEWER_JSON ${TEST_JAVA_SRC.joinToString(" ")}"
+        val cmd = CommandOptions(testLine.split(' ').toTypedArray())
+        assertEquals(CommandOptions.GENERATE_CONFIG_CMD, cmd.command)
+        assertEquals(TEST_PROTOLOG_CLASS, cmd.protoLogClassNameArg)
+        assertEquals(TEST_PROTOLOGGROUP_CLASS, cmd.protoLogGroupsClassNameArg)
+        assertEquals(TEST_PROTOLOGGROUP_JAR, cmd.protoLogGroupsJarArg)
+        assertEquals(TEST_VIEWER_JSON, cmd.viewerConfigFileNameArg)
+        assertEquals(TEST_JAVA_SRC, cmd.javaSourceArgs)
+    }
+
+    @Test
     fun generateConfig_noViewerConfig() {
         val testLine = "generate-viewer-config --protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
                 TEST_JAVA_SRC.joinToString(" ")
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("--viewer-config required")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun generateConfig_invalidViewerConfig() {
         val testLine = "generate-viewer-config --protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--viewer-conf invalid.yaml ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+                "--viewer-config invalid.yaml ${TEST_JAVA_SRC.joinToString(" ")}"
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("required, got invalid.yaml instead")
     }
 
     @Test
     fun readLog() {
-        val testLine = "read-log --viewer-conf $TEST_VIEWER_JSON $TEST_LOG"
+        val testLine = "read-log --viewer-config $TEST_VIEWER_JSON $TEST_LOG"
         val cmd = CommandOptions(testLine.split(' ').toTypedArray())
         assertEquals(CommandOptions.READ_LOG_CMD, cmd.command)
-        assertEquals(TEST_VIEWER_JSON, cmd.viewerConfigJsonArg)
+        assertEquals(TEST_VIEWER_JSON, cmd.viewerConfigFileNameArg)
         assertEquals(TEST_LOG, cmd.logProtofileArg)
     }
 }
diff --git a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
index 0d2b91d..822118c 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
@@ -16,22 +16,24 @@
 
 package com.android.protolog.tool
 
-import org.junit.Assert
-import org.junit.Assert.assertTrue
-import org.junit.Test
+import com.android.protolog.tool.ProtoLogTool.PROTOLOG_IMPL_SRC_PATH
+import com.google.common.truth.Truth
 import java.io.ByteArrayInputStream
 import java.io.ByteArrayOutputStream
 import java.io.File
 import java.io.FileNotFoundException
 import java.io.OutputStream
 import java.util.jar.JarInputStream
+import java.util.regex.Pattern
+import org.junit.Assert
+import org.junit.Test
 
 class EndToEndTest {
 
     @Test
     fun e2e_transform() {
         val output = run(
-                src = "frameworks/base/org/example/Example.java" to """
+                srcs = mapOf("frameworks/base/org/example/Example.java" to """
                     package org.example;
                     import com.android.internal.protolog.common.ProtoLog;
                     import static com.android.internal.protolog.ProtoLogGroup.GROUP;
@@ -43,26 +45,29 @@
                             ProtoLog.d(GROUP, "Example: %s %d", argString, argInt);
                         }
                     }
-                """.trimIndent(),
+                """.trimIndent()),
                 logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"),
                 commandOptions = CommandOptions(arrayOf("transform-protolog-calls",
                         "--protolog-class", "com.android.internal.protolog.common.ProtoLog",
-                        "--protolog-impl-class", "com.android.internal.protolog.ProtoLogImpl",
-                        "--protolog-cache-class",
-                        "com.android.server.wm.ProtoLogCache",
                         "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup",
                         "--loggroups-jar", "not_required.jar",
+                        "--viewer-config-file-path", "not_required.pb",
                         "--output-srcjar", "out.srcjar",
                         "frameworks/base/org/example/Example.java"))
         )
         val outSrcJar = assertLoadSrcJar(output, "out.srcjar")
-        assertTrue(" 2066303299," in outSrcJar["frameworks/base/org/example/Example.java"]!!)
+        Truth.assertThat(outSrcJar["frameworks/base/org/example/Example.java"])
+                .containsMatch(Pattern.compile("\\{ String protoLogParam0 = " +
+                        "String\\.valueOf\\(argString\\); long protoLogParam1 = argInt; " +
+                        "com\\.android\\.internal\\.protolog.ProtoLogImpl_.*\\.d\\(" +
+                        "GROUP, -6872339441335321086L, 4, null, protoLogParam0, protoLogParam1" +
+                        "\\); \\}"))
     }
 
     @Test
     fun e2e_viewerConfig() {
         val output = run(
-                src = "frameworks/base/org/example/Example.java" to """
+                srcs = mapOf("frameworks/base/org/example/Example.java" to """
                     package org.example;
                     import com.android.internal.protolog.common.ProtoLog;
                     import static com.android.internal.protolog.ProtoLogGroup.GROUP;
@@ -74,17 +79,27 @@
                             ProtoLog.d(GROUP, "Example: %s %d", argString, argInt);
                         }
                     }
-                """.trimIndent(),
+                """.trimIndent()),
                 logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"),
                 commandOptions = CommandOptions(arrayOf("generate-viewer-config",
                         "--protolog-class", "com.android.internal.protolog.common.ProtoLog",
                         "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup",
                         "--loggroups-jar", "not_required.jar",
-                        "--viewer-conf", "out.json",
+                        "--viewer-config-type", "json",
+                        "--viewer-config", "out.json",
                         "frameworks/base/org/example/Example.java"))
         )
         val viewerConfigJson = assertLoadText(output, "out.json")
-        assertTrue("\"2066303299\"" in viewerConfigJson)
+        Truth.assertThat(viewerConfigJson).contains("""
+            "messages": {
+                "-6872339441335321086": {
+                  "message": "Example: %s %d",
+                  "level": "DEBUG",
+                  "group": "GROUP",
+                  "at": "org\/example\/Example.java"
+                }
+              }
+        """.trimIndent())
     }
 
     private fun assertLoadSrcJar(
@@ -112,21 +127,46 @@
     }
 
     fun run(
-        src: Pair<String, String>,
+        srcs: Map<String, String>,
         logGroup: LogGroup,
         commandOptions: CommandOptions
     ): Map<String, ByteArray> {
         val outputs = mutableMapOf<String, ByteArrayOutputStream>()
 
+        val srcs = srcs.toMutableMap()
+        srcs[PROTOLOG_IMPL_SRC_PATH] = """
+            package com.android.internal.protolog;
+
+            import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LEGACY_OUTPUT_FILE_PATH;
+            import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LEGACY_VIEWER_CONFIG_PATH;
+            import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.VIEWER_CONFIG_PATH;
+
+            import com.android.internal.protolog.common.ProtoLogToolInjected;
+
+            public class ProtoLogImpl {
+                @ProtoLogToolInjected(VIEWER_CONFIG_PATH)
+                private static String sViewerConfigPath;
+
+                @ProtoLogToolInjected(LEGACY_VIEWER_CONFIG_PATH)
+                private static String sLegacyViewerConfigPath;
+
+                @ProtoLogToolInjected(LEGACY_OUTPUT_FILE_PATH)
+                private static String sLegacyOutputFilePath;
+            }
+        """.trimIndent()
+
         ProtoLogTool.injector = object : ProtoLogTool.Injector {
             override fun fileOutputStream(file: String): OutputStream =
                     ByteArrayOutputStream().also { outputs[file] = it }
 
             override fun readText(file: File): String {
-                if (file.path == src.first) {
-                    return src.second
+                for (src in srcs.entries) {
+                    val filePath = src.key
+                    if (file.path == filePath) {
+                        return src.value
+                    }
                 }
-                throw FileNotFoundException("expected: ${src.first}, but was $file")
+                throw FileNotFoundException("$file not found in [${srcs.keys.joinToString()}].")
             }
 
             override fun readLogGroups(jarPath: String, className: String) = mapOf(
diff --git a/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt b/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt
index 512d90c..1d32702 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt
@@ -35,7 +35,7 @@
 class LogParserTest {
     private val configParser: ViewerConfigParser = mock(ViewerConfigParser::class.java)
     private val parser = LogParser(configParser)
-    private var config: MutableMap<Int, ViewerConfigParser.ConfigEntry> = mutableMapOf()
+    private var config: MutableMap<Long, ViewerConfigParser.ConfigEntry> = mutableMapOf()
     private var outStream: OutputStream = ByteArrayOutputStream()
     private var printStream: PrintStream = PrintStream(outStream)
     private val dateFormat = SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US)
diff --git a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorImplTest.kt
similarity index 96%
rename from tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt
rename to tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorImplTest.kt
index 90b8059..5e50f71 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorImplTest.kt
@@ -22,7 +22,7 @@
 import org.junit.Assert.assertEquals
 import org.junit.Test
 
-class ProtoLogCallProcessorTest {
+class ProtoLogCallProcessorImplTest {
     private data class LogCall(
         val call: MethodCallExpr,
         val messageString: String,
@@ -32,8 +32,11 @@
 
     private val groupMap: MutableMap<String, LogGroup> = mutableMapOf()
     private val calls: MutableList<LogCall> = mutableListOf()
-    private val visitor = ProtoLogCallProcessor("org.example.ProtoLog", "org.example.ProtoLogGroup",
-            groupMap)
+    private val visitor = ProtoLogCallProcessorImpl(
+        "org.example.ProtoLog",
+        "org.example.ProtoLogGroup",
+            groupMap
+    )
     private val processor = object : ProtoLogCallVisitor {
         override fun processCall(
             call: MethodCallExpr,
diff --git a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogToolTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogToolTest.kt
deleted file mode 100644
index ea9a58d..0000000
--- a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogToolTest.kt
+++ /dev/null
@@ -1,52 +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.protolog.tool
-
-import org.junit.Assert.assertEquals
-import org.junit.Test
-
-class ProtoLogToolTest {
-
-    @Test
-    fun generateLogGroupCache() {
-        val groups = mapOf(
-                "GROUP1" to LogGroup("GROUP1", true, true, "TAG1"),
-                "GROUP2" to LogGroup("GROUP2", true, true, "TAG2")
-        )
-        val code = ProtoLogTool.generateLogGroupCache("org.example", "ProtoLog\$Cache",
-                groups, "org.example.ProtoLogImpl", "org.example.ProtoLogGroups")
-
-        assertEquals("""
-            package org.example;
-
-            public class ProtoLog${'$'}Cache {
-                public static boolean GROUP1_enabled = false;
-                public static boolean GROUP2_enabled = false;
-
-                static {
-                    org.example.ProtoLogImpl.sCacheUpdater = ProtoLog${'$'}Cache::update;
-                    update();
-                }
-
-                static void update() {
-                    GROUP1_enabled = org.example.ProtoLogImpl.isEnabled(org.example.ProtoLogGroups.GROUP1);
-                    GROUP2_enabled = org.example.ProtoLogImpl.isEnabled(org.example.ProtoLogGroups.GROUP2);
-                }
-            }
-        """.trimIndent(), code)
-    }
-}
\ No newline at end of file
diff --git a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
index f52bfec..de0b5ba 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
@@ -20,17 +20,14 @@
 import com.github.javaparser.StaticJavaParser
 import com.github.javaparser.ast.CompilationUnit
 import com.github.javaparser.ast.expr.MethodCallExpr
-import com.github.javaparser.ast.stmt.IfStmt
+import com.google.common.truth.Truth
 import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
 import org.junit.Test
 import org.mockito.Mockito
 
 class SourceTransformerTest {
     companion object {
-        private const val PROTO_LOG_IMPL_PATH = "org.example.ProtoLogImpl"
 
-        /* ktlint-disable max-line-length */
         private val TEST_CODE = """
             package org.example;
 
@@ -79,7 +76,7 @@
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); }
+                    { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); }
                 }
             }
             """.trimIndent()
@@ -89,20 +86,20 @@
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, 1780316587, 9, "test %d %f " + "abc %s\n test", protoLogParam0, protoLogParam1, protoLogParam2); 
+                    { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, -4447034859795564700L, 9, "test %d %f " + "abc %s\n test", protoLogParam0, protoLogParam1, protoLogParam2); 
             
             }
                 }
             }
             """.trimIndent()
 
-        private val TRANSFORMED_CODE_MULTICALL_TEXT_ENABLED = """
+        private val TRANSFORMED_CODE_MULTICALL_TEXT = """
             package org.example;
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); } /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); }
-                    if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); }
+                    { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); }
+                    { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); }
                 }
             }
             """.trimIndent()
@@ -112,7 +109,7 @@
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogCache.TEST_GROUP_enabled) { org.example.ProtoLogImpl.w(TEST_GROUP, -1741986185, 0, "test", (Object[]) null); }
+                    { org.example.ProtoLogImpl.w(TEST_GROUP, 3218600869538902408L, 0, "test", (Object[]) null); }
                 }
             }
             """.trimIndent()
@@ -122,7 +119,7 @@
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, null, protoLogParam0, protoLogParam1); }
+                    { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, null, protoLogParam0, protoLogParam1); }
                 }
             }
             """.trimIndent()
@@ -132,43 +129,19 @@
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, 1780316587, 9, null, protoLogParam0, protoLogParam1, protoLogParam2); 
+                    { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, -4447034859795564700L, 9, null, protoLogParam0, protoLogParam1, protoLogParam2); 
             
             }
                 }
             }
             """.trimIndent()
 
-        private val TRANSFORMED_CODE_DISABLED = """
-            package org.example;
-
-            class Test {
-                void test() {
-                    if (false) { /* TEST_GROUP is disabled */ ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); }
-                }
-            }
-            """.trimIndent()
-
-        private val TRANSFORMED_CODE_MULTILINE_DISABLED = """
-            package org.example;
-
-            class Test {
-                void test() {
-                    if (false) { /* TEST_GROUP is disabled */ ProtoLog.w(TEST_GROUP, "test %d %f " + "abc %s\n test", 100, 0.1, "test"); 
-            
-            }
-                }
-            }
-            """.trimIndent()
-        /* ktlint-enable max-line-length */
-
         private const val PATH = "com.example.Test.java"
     }
 
     private val processor: ProtoLogCallProcessor = Mockito.mock(ProtoLogCallProcessor::class.java)
     private val implName = "org.example.ProtoLogImpl"
-    private val cacheName = "org.example.ProtoLogCache"
-    private val sourceJarWriter = SourceTransformer(implName, cacheName, processor)
+    private val sourceJarWriter = SourceTransformer(implName, processor)
 
     private fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
 
@@ -176,9 +149,12 @@
     fun processClass_textEnabled() {
         var code = StaticJavaParser.parse(TEST_CODE)
 
-        Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
-                .thenAnswer { invocation ->
+        Mockito.`when`(processor.process(
+            any(CompilationUnit::class.java),
+            any(ProtoLogCallVisitor::class.java),
+            any(MethodCallVisitor::class.java),
+            any(String::class.java))
+        ).thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f",
@@ -190,18 +166,15 @@
         val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
-        val ifStmts = code.findAll(IfStmt::class.java)
-        assertEquals(1, ifStmts.size)
-        val ifStmt = ifStmts[0]
-        assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString())
-        assertFalse(ifStmt.elseStmt.isPresent)
-        assertEquals(3, ifStmt.thenStmt.childNodes.size)
-        val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[0] as MethodCallExpr
-        assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString())
+        val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
+            it.scope.orElse(null)?.toString() == implName
+        }
+        Truth.assertThat(protoLogCalls).hasSize(1)
+        val methodCall = protoLogCalls[0] as MethodCallExpr
         assertEquals("w", methodCall.name.asString())
         assertEquals(6, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("1698911065", methodCall.arguments[1].toString())
+        assertEquals("-1473209266730422156L", methodCall.arguments[1].toString())
         assertEquals(0b1001.toString(), methodCall.arguments[2].toString())
         assertEquals("\"test %d %f\"", methodCall.arguments[3].toString())
         assertEquals("protoLogParam0", methodCall.arguments[4].toString())
@@ -213,9 +186,12 @@
     fun processClass_textEnabledMulticalls() {
         var code = StaticJavaParser.parse(TEST_CODE_MULTICALLS)
 
-        Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
-                .thenAnswer { invocation ->
+        Mockito.`when`(processor.process(
+            any(CompilationUnit::class.java),
+            any(ProtoLogCallVisitor::class.java),
+            any(MethodCallVisitor::class.java),
+            any(String::class.java))
+        ).thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             val calls = code.findAll(MethodCallExpr::class.java)
@@ -232,32 +208,32 @@
         val out = sourceJarWriter.processClass(TEST_CODE_MULTICALLS, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
-        val ifStmts = code.findAll(IfStmt::class.java)
-        assertEquals(3, ifStmts.size)
-        val ifStmt = ifStmts[1]
-        assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString())
-        assertFalse(ifStmt.elseStmt.isPresent)
-        assertEquals(3, ifStmt.thenStmt.childNodes.size)
-        val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[0] as MethodCallExpr
-        assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString())
+        val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
+            it.scope.orElse(null)?.toString() == implName
+        }
+        Truth.assertThat(protoLogCalls).hasSize(3)
+        val methodCall = protoLogCalls[0] as MethodCallExpr
         assertEquals("w", methodCall.name.asString())
         assertEquals(6, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("1698911065", methodCall.arguments[1].toString())
+        assertEquals("-1473209266730422156L", methodCall.arguments[1].toString())
         assertEquals(0b1001.toString(), methodCall.arguments[2].toString())
         assertEquals("\"test %d %f\"", methodCall.arguments[3].toString())
         assertEquals("protoLogParam0", methodCall.arguments[4].toString())
         assertEquals("protoLogParam1", methodCall.arguments[5].toString())
-        assertEquals(TRANSFORMED_CODE_MULTICALL_TEXT_ENABLED, out)
+        assertEquals(TRANSFORMED_CODE_MULTICALL_TEXT, out)
     }
 
     @Test
     fun processClass_textEnabledMultiline() {
         var code = StaticJavaParser.parse(TEST_CODE_MULTILINE)
 
-        Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
-                .thenAnswer { invocation ->
+        Mockito.`when`(processor.process(
+            any(CompilationUnit::class.java),
+            any(ProtoLogCallVisitor::class.java),
+            any(MethodCallVisitor::class.java),
+            any(String::class.java))
+        ).thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(code.findAll(MethodCallExpr::class.java)[0],
@@ -270,18 +246,15 @@
         val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
-        val ifStmts = code.findAll(IfStmt::class.java)
-        assertEquals(1, ifStmts.size)
-        val ifStmt = ifStmts[0]
-        assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString())
-        assertFalse(ifStmt.elseStmt.isPresent)
-        assertEquals(4, ifStmt.thenStmt.childNodes.size)
-        val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[1] as MethodCallExpr
-        assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString())
+        val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
+            it.scope.orElse(null)?.toString() == implName
+        }
+        Truth.assertThat(protoLogCalls).hasSize(1)
+        val methodCall = protoLogCalls[0] as MethodCallExpr
         assertEquals("w", methodCall.name.asString())
         assertEquals(7, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("1780316587", methodCall.arguments[1].toString())
+        assertEquals("-4447034859795564700L", methodCall.arguments[1].toString())
         assertEquals(0b001001.toString(), methodCall.arguments[2].toString())
         assertEquals("protoLogParam0", methodCall.arguments[4].toString())
         assertEquals("protoLogParam1", methodCall.arguments[5].toString())
@@ -293,9 +266,12 @@
     fun processClass_noParams() {
         var code = StaticJavaParser.parse(TEST_CODE_NO_PARAMS)
 
-        Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
-                .thenAnswer { invocation ->
+        Mockito.`when`(processor.process(
+            any(CompilationUnit::class.java),
+            any(ProtoLogCallVisitor::class.java),
+            any(MethodCallVisitor::class.java),
+            any(String::class.java))
+        ).thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test",
@@ -307,18 +283,15 @@
         val out = sourceJarWriter.processClass(TEST_CODE_NO_PARAMS, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
-        val ifStmts = code.findAll(IfStmt::class.java)
-        assertEquals(1, ifStmts.size)
-        val ifStmt = ifStmts[0]
-        assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString())
-        assertFalse(ifStmt.elseStmt.isPresent)
-        assertEquals(1, ifStmt.thenStmt.childNodes.size)
-        val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[0] as MethodCallExpr
-        assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString())
+        val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
+            it.scope.orElse(null)?.toString() == implName
+        }
+        Truth.assertThat(protoLogCalls).hasSize(1)
+        val methodCall = protoLogCalls[0] as MethodCallExpr
         assertEquals("w", methodCall.name.asString())
         assertEquals(5, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("-1741986185", methodCall.arguments[1].toString())
+        assertEquals("3218600869538902408L", methodCall.arguments[1].toString())
         assertEquals(0.toString(), methodCall.arguments[2].toString())
         assertEquals(TRANSFORMED_CODE_NO_PARAMS, out)
     }
@@ -327,9 +300,12 @@
     fun processClass_textDisabled() {
         var code = StaticJavaParser.parse(TEST_CODE)
 
-        Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
-                .thenAnswer { invocation ->
+        Mockito.`when`(processor.process(
+            any(CompilationUnit::class.java),
+            any(ProtoLogCallVisitor::class.java),
+            any(MethodCallVisitor::class.java),
+            any(String::class.java))
+        ).thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f",
@@ -341,18 +317,15 @@
         val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
-        val ifStmts = code.findAll(IfStmt::class.java)
-        assertEquals(1, ifStmts.size)
-        val ifStmt = ifStmts[0]
-        assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString())
-        assertFalse(ifStmt.elseStmt.isPresent)
-        assertEquals(3, ifStmt.thenStmt.childNodes.size)
-        val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[0] as MethodCallExpr
-        assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString())
+        val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
+            it.scope.orElse(null)?.toString() == implName
+        }
+        Truth.assertThat(protoLogCalls).hasSize(1)
+        val methodCall = protoLogCalls[0] as MethodCallExpr
         assertEquals("w", methodCall.name.asString())
         assertEquals(6, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("1698911065", methodCall.arguments[1].toString())
+        assertEquals("-1473209266730422156L", methodCall.arguments[1].toString())
         assertEquals(0b1001.toString(), methodCall.arguments[2].toString())
         assertEquals("null", methodCall.arguments[3].toString())
         assertEquals("protoLogParam0", methodCall.arguments[4].toString())
@@ -364,9 +337,12 @@
     fun processClass_textDisabledMultiline() {
         var code = StaticJavaParser.parse(TEST_CODE_MULTILINE)
 
-        Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
-                .thenAnswer { invocation ->
+        Mockito.`when`(processor.process(
+            any(CompilationUnit::class.java),
+            any(ProtoLogCallVisitor::class.java),
+            any(MethodCallVisitor::class.java),
+            any(String::class.java))
+        ).thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(code.findAll(MethodCallExpr::class.java)[0],
@@ -379,18 +355,15 @@
         val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
-        val ifStmts = code.findAll(IfStmt::class.java)
-        assertEquals(1, ifStmts.size)
-        val ifStmt = ifStmts[0]
-        assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString())
-        assertFalse(ifStmt.elseStmt.isPresent)
-        assertEquals(4, ifStmt.thenStmt.childNodes.size)
-        val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[1] as MethodCallExpr
-        assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString())
+        val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
+            it.scope.orElse(null)?.toString() == implName
+        }
+        Truth.assertThat(protoLogCalls).hasSize(1)
+        val methodCall = protoLogCalls[0] as MethodCallExpr
         assertEquals("w", methodCall.name.asString())
         assertEquals(7, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("1780316587", methodCall.arguments[1].toString())
+        assertEquals("-4447034859795564700L", methodCall.arguments[1].toString())
         assertEquals(0b001001.toString(), methodCall.arguments[2].toString())
         assertEquals("null", methodCall.arguments[3].toString())
         assertEquals("protoLogParam0", methodCall.arguments[4].toString())
@@ -398,55 +371,4 @@
         assertEquals("protoLogParam2", methodCall.arguments[6].toString())
         assertEquals(TRANSFORMED_CODE_MULTILINE_TEXT_DISABLED, out)
     }
-
-    @Test
-    fun processClass_disabled() {
-        var code = StaticJavaParser.parse(TEST_CODE)
-
-        Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
-                .thenAnswer { invocation ->
-            val visitor = invocation.arguments[1] as ProtoLogCallVisitor
-
-            visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f",
-                    LogLevel.WARN, LogGroup("TEST_GROUP", false, true, "WM_TEST"))
-
-            invocation.arguments[0] as CompilationUnit
-        }
-
-        val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code)
-        code = StaticJavaParser.parse(out)
-
-        val ifStmts = code.findAll(IfStmt::class.java)
-        assertEquals(1, ifStmts.size)
-        val ifStmt = ifStmts[0]
-        assertEquals("false", ifStmt.condition.toString())
-        assertEquals(TRANSFORMED_CODE_DISABLED, out)
-    }
-
-    @Test
-    fun processClass_disabledMultiline() {
-        var code = StaticJavaParser.parse(TEST_CODE_MULTILINE)
-
-        Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
-                .thenAnswer { invocation ->
-            val visitor = invocation.arguments[1] as ProtoLogCallVisitor
-
-            visitor.processCall(code.findAll(MethodCallExpr::class.java)[0],
-                    "test %d %f abc %s\n test", LogLevel.WARN, LogGroup("TEST_GROUP",
-                    false, true, "WM_TEST"))
-
-            invocation.arguments[0] as CompilationUnit
-        }
-
-        val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code)
-        code = StaticJavaParser.parse(out)
-
-        val ifStmts = code.findAll(IfStmt::class.java)
-        assertEquals(1, ifStmts.size)
-        val ifStmt = ifStmts[0]
-        assertEquals("false", ifStmt.condition.toString())
-        assertEquals(TRANSFORMED_CODE_MULTILINE_DISABLED, out)
-    }
 }
diff --git a/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigJsonBuilderTest.kt
similarity index 66%
rename from tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt
rename to tools/protologtool/tests/com/android/protolog/tool/ViewerConfigJsonBuilderTest.kt
index 52dce21..d27ae88 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigJsonBuilderTest.kt
@@ -18,13 +18,12 @@
 
 import com.android.internal.protolog.common.LogLevel
 import com.android.json.stream.JsonReader
-import com.android.protolog.tool.ViewerConfigBuilder.LogCall
+import com.android.protolog.tool.ProtoLogTool.LogCall
+import java.io.StringReader
 import org.junit.Assert.assertEquals
 import org.junit.Test
-import org.mockito.Mockito
-import java.io.StringReader
 
-class ViewerConfigBuilderTest {
+class ViewerConfigJsonBuilderTest {
     companion object {
         private val TAG1 = "WM_TEST"
         private val TAG2 = "WM_DEBUG"
@@ -39,20 +38,22 @@
         private const val PATH = "/tmp/test.java"
     }
 
-    private val configBuilder = ViewerConfigBuilder(Mockito.mock(ProtoLogCallProcessor::class.java))
+    private val configBuilder = ViewerConfigJsonBuilder()
 
-    private fun parseConfig(json: String): Map<Int, ViewerConfigParser.ConfigEntry> {
+    private fun parseConfig(json: String): Map<Long, ViewerConfigParser.ConfigEntry> {
         return ViewerConfigParser().parseConfig(JsonReader(StringReader(json)))
     }
 
     @Test
     fun processClass() {
-        configBuilder.addLogCalls(listOf(
+        val logCallRegistry = ProtoLogTool.LogCallRegistry()
+        logCallRegistry.addLogCalls(listOf(
                 LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH),
                 LogCall(TEST2.messageString, LogLevel.DEBUG, GROUP2, PATH),
-                LogCall(TEST3.messageString, LogLevel.ERROR, GROUP3, PATH)).withContext())
+                LogCall(TEST3.messageString, LogLevel.ERROR, GROUP3, PATH)))
 
-        val parsedConfig = parseConfig(configBuilder.build())
+        val parsedConfig = parseConfig(
+            configBuilder.build(logCallRegistry.getStatements()).toString(Charsets.UTF_8))
         assertEquals(3, parsedConfig.size)
         assertEquals(TEST1, parsedConfig[CodeUtils.hash(PATH,
 	           TEST1.messageString, LogLevel.INFO, GROUP1)])
@@ -64,32 +65,16 @@
 
     @Test
     fun processClass_nonUnique() {
-        configBuilder.addLogCalls(listOf(
+        val logCallRegistry = ProtoLogTool.LogCallRegistry()
+        logCallRegistry.addLogCalls(listOf(
                 LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH),
                 LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH),
-                LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH)).withContext())
+                LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH)))
 
-        val parsedConfig = parseConfig(configBuilder.build())
+        val parsedConfig = parseConfig(
+            configBuilder.build(logCallRegistry.getStatements()).toString(Charsets.UTF_8))
         assertEquals(1, parsedConfig.size)
         assertEquals(TEST1, parsedConfig[CodeUtils.hash(PATH, TEST1.messageString,
-            	   LogLevel.INFO, GROUP1)])
+            LogLevel.INFO, GROUP1)])
     }
-
-    @Test
-    fun processClass_disabled() {
-        configBuilder.addLogCalls(listOf(
-                LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH),
-                LogCall(TEST2.messageString, LogLevel.DEBUG, GROUP_DISABLED, PATH),
-                LogCall(TEST3.messageString, LogLevel.ERROR, GROUP_TEXT_DISABLED, PATH))
-                .withContext())
-
-        val parsedConfig = parseConfig(configBuilder.build())
-        assertEquals(2, parsedConfig.size)
-        assertEquals(TEST1, parsedConfig[CodeUtils.hash(
-                PATH, TEST1.messageString, LogLevel.INFO, GROUP1)])
-        assertEquals(TEST3, parsedConfig[CodeUtils.hash(
-                PATH, TEST3.messageString, LogLevel.ERROR, GROUP_TEXT_DISABLED)])
-    }
-
-    private fun List<LogCall>.withContext() = map { it to ParsingContext() }
 }